@lenne.tech/cli 1.9.6 → 1.11.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.
Files changed (38) hide show
  1. package/README.md +88 -3
  2. package/build/commands/config/validate.js +2 -0
  3. package/build/commands/frontend/convert-mode.js +198 -0
  4. package/build/commands/fullstack/convert-mode.js +368 -0
  5. package/build/commands/fullstack/init.js +150 -4
  6. package/build/commands/fullstack/update.js +177 -0
  7. package/build/commands/server/add-property.js +29 -2
  8. package/build/commands/server/convert-mode.js +197 -0
  9. package/build/commands/server/create.js +41 -3
  10. package/build/commands/server/module.js +58 -25
  11. package/build/commands/server/object.js +26 -5
  12. package/build/commands/server/permissions.js +20 -6
  13. package/build/commands/server/test.js +7 -1
  14. package/build/commands/status.js +94 -3
  15. package/build/config/vendor-frontend-runtime-deps.json +4 -0
  16. package/build/config/vendor-runtime-deps.json +9 -0
  17. package/build/extensions/api-mode.js +19 -3
  18. package/build/extensions/frontend-helper.js +652 -0
  19. package/build/extensions/server.js +1475 -3
  20. package/build/lib/framework-detection.js +167 -0
  21. package/build/lib/frontend-framework-detection.js +129 -0
  22. package/build/templates/nest-server-module/inputs/template-create.input.ts.ejs +1 -1
  23. package/build/templates/nest-server-module/inputs/template.input.ts.ejs +1 -1
  24. package/build/templates/nest-server-module/outputs/template-fac-result.output.ts.ejs +1 -1
  25. package/build/templates/nest-server-module/template.controller.ts.ejs +1 -1
  26. package/build/templates/nest-server-module/template.model.ts.ejs +1 -1
  27. package/build/templates/nest-server-module/template.module.ts.ejs +1 -1
  28. package/build/templates/nest-server-module/template.resolver.ts.ejs +1 -1
  29. package/build/templates/nest-server-module/template.service.ts.ejs +1 -1
  30. package/build/templates/nest-server-object/template-create.input.ts.ejs +1 -1
  31. package/build/templates/nest-server-object/template.input.ts.ejs +1 -1
  32. package/build/templates/nest-server-object/template.object.ts.ejs +1 -1
  33. package/build/templates/nest-server-tests/tests.e2e-spec.ts.ejs +1 -1
  34. package/docs/LT-ECOSYSTEM-GUIDE.md +973 -0
  35. package/docs/VENDOR-MODE-WORKFLOW.md +471 -0
  36. package/docs/commands.md +196 -0
  37. package/docs/lt.config.md +9 -7
  38. package/package.json +17 -8
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ /**
3
+ * Framework-detection helpers for @lenne.tech/nest-server consumer projects.
4
+ *
5
+ * lenne.tech API projects can consume the framework in two modes:
6
+ *
7
+ * - **npm mode** (classic): `@lenne.tech/nest-server` is installed as an npm
8
+ * dependency. Framework source lives in
9
+ * `node_modules/@lenne.tech/nest-server/`. Generated code uses bare
10
+ * specifiers (`from '@lenne.tech/nest-server'`).
11
+ *
12
+ * - **vendored mode**: The framework's `core/` directory is copied directly
13
+ * into the project at `<api-root>/src/core/` as first-class project code.
14
+ * There is **no** `@lenne.tech/nest-server` dependency in `package.json`.
15
+ * Generated code uses relative imports (`from '../../../core'`, depth
16
+ * varies by file location).
17
+ *
18
+ * The detection is driven by the presence of `<api-root>/src/core/VENDOR.md`
19
+ * (a baseline + patch-log file written by the vendoring pilot).
20
+ *
21
+ * This module centralizes the detection logic so that every CLI command which
22
+ * emits or patches nest-server-aware code can branch consistently.
23
+ */
24
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ var desc = Object.getOwnPropertyDescriptor(m, k);
27
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
28
+ desc = { enumerable: true, get: function() { return m[k]; } };
29
+ }
30
+ Object.defineProperty(o, k2, desc);
31
+ }) : (function(o, m, k, k2) {
32
+ if (k2 === undefined) k2 = k;
33
+ o[k2] = m[k];
34
+ }));
35
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
36
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
37
+ }) : function(o, v) {
38
+ o["default"] = v;
39
+ });
40
+ var __importStar = (this && this.__importStar) || (function () {
41
+ var ownKeys = function(o) {
42
+ ownKeys = Object.getOwnPropertyNames || function (o) {
43
+ var ar = [];
44
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
45
+ return ar;
46
+ };
47
+ return ownKeys(o);
48
+ };
49
+ return function (mod) {
50
+ if (mod && mod.__esModule) return mod;
51
+ var result = {};
52
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
53
+ __setModuleDefault(result, mod);
54
+ return result;
55
+ };
56
+ })();
57
+ Object.defineProperty(exports, "__esModule", { value: true });
58
+ exports.detectFrameworkMode = detectFrameworkMode;
59
+ exports.findProjectDir = findProjectDir;
60
+ exports.getFrameworkImportSpecifier = getFrameworkImportSpecifier;
61
+ exports.getFrameworkRootPath = getFrameworkRootPath;
62
+ exports.isVendoredProject = isVendoredProject;
63
+ const node_fs_1 = require("node:fs");
64
+ const path = __importStar(require("node:path"));
65
+ /**
66
+ * Determines the current framework consumption mode of the given project.
67
+ *
68
+ * Returns `'vendor'` if `VENDOR.md` indicates vendored mode. Otherwise
69
+ * returns `'npm'` (the classic mode where `@lenne.tech/nest-server` is an
70
+ * npm dependency).
71
+ */
72
+ function detectFrameworkMode(projectDir) {
73
+ return isVendoredProject(projectDir) ? 'vendor' : 'npm';
74
+ }
75
+ /**
76
+ * Walks up from `startDir` looking for the nearest `package.json`, returning
77
+ * the directory that contains it. Used by commands that are invoked from a
78
+ * sub-directory of an API project and need to find the project root.
79
+ *
80
+ * Returns `undefined` if no `package.json` is found up to the filesystem root.
81
+ */
82
+ function findProjectDir(startDir) {
83
+ let current = path.resolve(startDir);
84
+ const root = path.parse(current).root;
85
+ while (current !== root) {
86
+ if ((0, node_fs_1.existsSync)(path.join(current, 'package.json'))) {
87
+ return current;
88
+ }
89
+ current = path.dirname(current);
90
+ }
91
+ return undefined;
92
+ }
93
+ /**
94
+ * Returns the import specifier to use for `from '<framework>'` in generated
95
+ * source code living at `sourceFilePath`.
96
+ *
97
+ * - npm mode: always `'@lenne.tech/nest-server'` (bare specifier).
98
+ * - vendor mode: a relative path from `sourceFilePath`'s directory to
99
+ * `<projectDir>/src/core`, normalized to forward slashes and
100
+ * prefixed with `./` if needed. Example: for
101
+ * `projectDir/src/server/modules/foo/foo.service.ts`, returns
102
+ * `'../../../core'`.
103
+ *
104
+ * `sourceFilePath` is the absolute path of the file that WILL CONTAIN the
105
+ * import — NOT the file being imported. Depth is calculated from this path.
106
+ *
107
+ * @example
108
+ * // Project at /abs/api, file at src/server/modules/foo/foo.service.ts
109
+ * getFrameworkImportSpecifier('/abs/api',
110
+ * '/abs/api/src/server/modules/foo/foo.service.ts');
111
+ * // → '../../../core' (vendor mode)
112
+ * // → '@lenne.tech/nest-server' (npm mode)
113
+ */
114
+ function getFrameworkImportSpecifier(projectDir, sourceFilePath) {
115
+ if (!isVendoredProject(projectDir)) {
116
+ return '@lenne.tech/nest-server';
117
+ }
118
+ const corePath = path.join(projectDir, 'src', 'core');
119
+ const fromDir = path.dirname(sourceFilePath);
120
+ let rel = path.relative(fromDir, corePath);
121
+ // Normalize to POSIX separators (import specifiers are always forward-slash)
122
+ rel = rel.split(path.sep).join('/');
123
+ // Guarantee a relative prefix; sibling or descendant paths otherwise miss `./`
124
+ if (!rel.startsWith('.')) {
125
+ rel = `./${rel}`;
126
+ }
127
+ return rel;
128
+ }
129
+ /**
130
+ * Returns the filesystem root of the framework source for the project.
131
+ *
132
+ * - npm mode: `<projectDir>/node_modules/@lenne.tech/nest-server`
133
+ * - vendor mode: `<projectDir>/src/core`
134
+ *
135
+ * Consumers that need to introspect framework source files (e.g. permissions
136
+ * scanner, CrudService lookup) should use this instead of hard-coding either
137
+ * path.
138
+ */
139
+ function getFrameworkRootPath(projectDir) {
140
+ return isVendoredProject(projectDir)
141
+ ? path.join(projectDir, 'src', 'core')
142
+ : path.join(projectDir, 'node_modules', '@lenne.tech', 'nest-server');
143
+ }
144
+ /**
145
+ * Detects whether the given API project directory runs in vendored mode.
146
+ *
147
+ * A project is considered vendored when:
148
+ * 1. `<projectDir>/src/core/VENDOR.md` exists, AND
149
+ * 2. The VENDOR.md content references `@lenne.tech/nest-server` (guards
150
+ * against coincidental unrelated `VENDOR.md` files).
151
+ *
152
+ * @param projectDir Absolute path to the api project (the directory that
153
+ * contains `package.json` and `src/`).
154
+ */
155
+ function isVendoredProject(projectDir) {
156
+ const vendorMd = path.join(projectDir, 'src', 'core', 'VENDOR.md');
157
+ if (!(0, node_fs_1.existsSync)(vendorMd)) {
158
+ return false;
159
+ }
160
+ try {
161
+ const content = (0, node_fs_1.readFileSync)(vendorMd, 'utf-8');
162
+ return content.includes('@lenne.tech/nest-server');
163
+ }
164
+ catch (_a) {
165
+ return false;
166
+ }
167
+ }
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ /**
3
+ * Framework-detection helpers for @lenne.tech/nuxt-extensions consumer projects.
4
+ *
5
+ * lenne.tech frontend projects can consume the framework in two modes:
6
+ *
7
+ * - **npm mode** (classic): `@lenne.tech/nuxt-extensions` is installed as an npm
8
+ * dependency. Framework source lives in
9
+ * `node_modules/@lenne.tech/nuxt-extensions/`. The Nuxt config references
10
+ * the module via `modules: ['@lenne.tech/nuxt-extensions']`.
11
+ *
12
+ * - **vendored mode**: The framework's source is copied directly
13
+ * into the project at `<app-root>/app/core/` as first-class project code.
14
+ * There is **no** `@lenne.tech/nuxt-extensions` dependency in `package.json`.
15
+ * The Nuxt config references `modules: ['./app/core/module']`.
16
+ *
17
+ * The detection is driven by the presence of `<app-root>/app/core/VENDOR.md`
18
+ * (a baseline + patch-log file written by the vendoring pipeline).
19
+ *
20
+ * This module centralizes the detection logic so that every CLI command which
21
+ * emits or patches nuxt-extensions-aware code can branch consistently.
22
+ */
23
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ var desc = Object.getOwnPropertyDescriptor(m, k);
26
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
27
+ desc = { enumerable: true, get: function() { return m[k]; } };
28
+ }
29
+ Object.defineProperty(o, k2, desc);
30
+ }) : (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ o[k2] = m[k];
33
+ }));
34
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
35
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
36
+ }) : function(o, v) {
37
+ o["default"] = v;
38
+ });
39
+ var __importStar = (this && this.__importStar) || (function () {
40
+ var ownKeys = function(o) {
41
+ ownKeys = Object.getOwnPropertyNames || function (o) {
42
+ var ar = [];
43
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
44
+ return ar;
45
+ };
46
+ return ownKeys(o);
47
+ };
48
+ return function (mod) {
49
+ if (mod && mod.__esModule) return mod;
50
+ var result = {};
51
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
52
+ __setModuleDefault(result, mod);
53
+ return result;
54
+ };
55
+ })();
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ exports.detectFrontendFrameworkMode = detectFrontendFrameworkMode;
58
+ exports.findAppDir = findAppDir;
59
+ exports.getFrontendFrameworkRootPath = getFrontendFrameworkRootPath;
60
+ exports.isVendoredAppProject = isVendoredAppProject;
61
+ const node_fs_1 = require("node:fs");
62
+ const path = __importStar(require("node:path"));
63
+ /**
64
+ * Determines the current frontend framework consumption mode of the given project.
65
+ *
66
+ * Returns `'vendor'` if `VENDOR.md` indicates vendored mode. Otherwise
67
+ * returns `'npm'` (the classic mode where `@lenne.tech/nuxt-extensions` is an
68
+ * npm dependency).
69
+ */
70
+ function detectFrontendFrameworkMode(appDir) {
71
+ return isVendoredAppProject(appDir) ? 'vendor' : 'npm';
72
+ }
73
+ /**
74
+ * Walks up from `startDir` looking for the nearest `nuxt.config.ts` (or
75
+ * `nuxt.config.js`), returning the directory that contains it. Used by
76
+ * commands invoked from a sub-directory of a frontend project.
77
+ *
78
+ * Returns `undefined` if no Nuxt config is found up to the filesystem root.
79
+ */
80
+ function findAppDir(startDir) {
81
+ let current = path.resolve(startDir);
82
+ const root = path.parse(current).root;
83
+ while (current !== root) {
84
+ if ((0, node_fs_1.existsSync)(path.join(current, 'nuxt.config.ts')) ||
85
+ (0, node_fs_1.existsSync)(path.join(current, 'nuxt.config.js'))) {
86
+ return current;
87
+ }
88
+ current = path.dirname(current);
89
+ }
90
+ return undefined;
91
+ }
92
+ /**
93
+ * Returns the filesystem root of the frontend framework source for the project.
94
+ *
95
+ * - npm mode: `<appDir>/node_modules/@lenne.tech/nuxt-extensions`
96
+ * - vendor mode: `<appDir>/app/core`
97
+ *
98
+ * Consumers that need to introspect framework source files should use this
99
+ * instead of hard-coding either path.
100
+ */
101
+ function getFrontendFrameworkRootPath(appDir) {
102
+ return isVendoredAppProject(appDir)
103
+ ? path.join(appDir, 'app', 'core')
104
+ : path.join(appDir, 'node_modules', '@lenne.tech', 'nuxt-extensions');
105
+ }
106
+ /**
107
+ * Detects whether the given frontend project directory runs in vendored mode.
108
+ *
109
+ * A project is considered vendored when:
110
+ * 1. `<appDir>/app/core/VENDOR.md` exists, AND
111
+ * 2. The VENDOR.md content references `@lenne.tech/nuxt-extensions` (guards
112
+ * against coincidental unrelated `VENDOR.md` files).
113
+ *
114
+ * @param appDir Absolute path to the frontend project (the directory that
115
+ * contains `nuxt.config.ts` and `app/`).
116
+ */
117
+ function isVendoredAppProject(appDir) {
118
+ const vendorMd = path.join(appDir, 'app', 'core', 'VENDOR.md');
119
+ if (!(0, node_fs_1.existsSync)(vendorMd)) {
120
+ return false;
121
+ }
122
+ try {
123
+ const content = (0, node_fs_1.readFileSync)(vendorMd, 'utf-8');
124
+ return content.includes('@lenne.tech/nuxt-extensions');
125
+ }
126
+ catch (_a) {
127
+ return false;
128
+ }
129
+ }
@@ -1,4 +1,4 @@
1
- import { Restricted, RoleEnum, UnifiedField } from '@lenne.tech/nest-server';
1
+ import { Restricted, RoleEnum, UnifiedField } from '<%= props.frameworkImport %>';
2
2
  import { InputType } from '@nestjs/graphql';
3
3
  import { <%= props.namePascal %>Input } from './<%= props.nameKebab %>.input';<%- props.imports %>
4
4
 
@@ -1,4 +1,4 @@
1
- import { CoreInput, Restricted, RoleEnum, UnifiedField } from '@lenne.tech/nest-server';
1
+ import { CoreInput, Restricted, RoleEnum, UnifiedField } from '<%= props.frameworkImport %>';
2
2
  import { InputType } from '@nestjs/graphql';<%- props.imports %>
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { UnifiedField } from '@lenne.tech/nest-server';
1
+ import { UnifiedField } from '<%= props.frameworkImport %>';
2
2
  <% if (props.isGql) { %>
3
3
  import { ObjectType } from '@nestjs/graphql';
4
4
  <% } %>
@@ -1,4 +1,4 @@
1
- import { ApiCommonErrorResponses, FilterArgs, RoleEnum, Roles } from '@lenne.tech/nest-server';
1
+ import { ApiCommonErrorResponses, FilterArgs, RoleEnum, Roles } from '<%= props.frameworkImport %>';
2
2
  import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common';
3
3
  import { ApiOkResponse } from '@nestjs/swagger';
4
4
 
@@ -1,4 +1,4 @@
1
- import { Restricted, RoleEnum, equalIds<% if (props.mappings.includes('mapClasses')) { %>, mapClasses<% } %>, UnifiedField} from '@lenne.tech/nest-server';
1
+ import { Restricted, RoleEnum, equalIds<% if (props.mappings.includes('mapClasses')) { %>, mapClasses<% } %>, UnifiedField} from '<%= props.frameworkImport %>';
2
2
  <% if (props.isGql) { %>
3
3
  import { ObjectType } from '@nestjs/graphql';
4
4
  <% } %>
@@ -1,4 +1,4 @@
1
- import { ConfigService } from '@lenne.tech/nest-server';
1
+ import { ConfigService } from '<%= props.frameworkImport %>';
2
2
  import { Module, forwardRef } from '@nestjs/common';
3
3
  import { MongooseModule } from '@nestjs/mongoose';
4
4
  <% if ((props.controller === 'GraphQL') || (props.controller === 'Both')) { -%>
@@ -1,4 +1,4 @@
1
- import { FilterArgs, GraphQLServiceOptions, RoleEnum, Roles, ServiceOptions } from '@lenne.tech/nest-server';
1
+ import { FilterArgs, GraphQLServiceOptions, RoleEnum, Roles, ServiceOptions } from '<%= props.frameworkImport %>';
2
2
  import { Inject } from '@nestjs/common';
3
3
  import { Args, Mutation, Query, Resolver, Subscription } from '@nestjs/graphql';
4
4
  import { PubSub } from 'graphql-subscriptions';
@@ -1,4 +1,4 @@
1
- import { ConfigService, CrudService, ServiceOptions, assignPlain } from '@lenne.tech/nest-server';
1
+ import { ConfigService, CrudService, ServiceOptions, assignPlain } from '<%= props.frameworkImport %>';
2
2
  import { Inject, Injectable, NotFoundException } from '@nestjs/common';
3
3
  import { InjectModel } from '@nestjs/mongoose';
4
4
  <% if (props.isGql) { %>import { PubSub } from 'graphql-subscriptions';
@@ -1,4 +1,4 @@
1
- import { Restricted, RoleEnum, UnifiedField } from '@lenne.tech/nest-server';
1
+ import { Restricted, RoleEnum, UnifiedField } from '<%= props.frameworkImport %>';
2
2
  import { InputType } from '@nestjs/graphql';
3
3
  import { <%= props.namePascal %>Input } from './<%= props.nameKebab %>.input';<%- props.imports %>
4
4
 
@@ -1,4 +1,4 @@
1
- import { CoreInput, Restricted, RoleEnum, UnifiedField } from '@lenne.tech/nest-server';
1
+ import { CoreInput, Restricted, RoleEnum, UnifiedField } from '<%= props.frameworkImport %>';
2
2
  import { InputType } from '@nestjs/graphql';<%- props.imports %>
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { CoreModel, Restricted, RoleEnum<% if (props.mappings.includes('mapClasses')) { %>, mapClasses<% } %>, UnifiedField } from '@lenne.tech/nest-server';
1
+ import { CoreModel, Restricted, RoleEnum<% if (props.mappings.includes('mapClasses')) { %>, mapClasses<% } %>, UnifiedField } from '<%= props.frameworkImport %>';
2
2
  import { ObjectType } from '@nestjs/graphql';
3
3
  import { Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
4
4
  import { Document } from 'mongoose';<%- props.imports %>
@@ -1,4 +1,4 @@
1
- import { RoleEnum, TestGraphQLType, TestHelper } from '@lenne.tech/nest-server';
1
+ import { RoleEnum, TestGraphQLType, TestHelper } from '<%= props.frameworkImport %>';
2
2
  import { Test, TestingModule } from '@nestjs/testing';
3
3
  import { PubSub } from 'graphql-subscriptions';
4
4
  import envConfig from '../src/config.env';