@ojiepermana/angular-sdk 22.0.27

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 ADDED
@@ -0,0 +1,252 @@
1
+ # SDK Generator
2
+
3
+ OpenAPI → Angular SDK generator shipped as the secondary entrypoint
4
+ `@ojiepermana/angular/generator/api`.
5
+
6
+ It generates a **lightweight Angular SDK** from any OpenAPI 3.x spec (including
7
+ 3.2.0): typed `HttpClient` services, tree-shakeable fn modules, optional
8
+ metadata (permissions / validators), and a navigation tree.
9
+
10
+ ## Local development in this repo
11
+
12
+ ```bash
13
+ # 1. Build the schematic runtime
14
+ bun run gen:sdk:build
15
+
16
+ # 2. Scaffold a workspace config
17
+ bun run gen:sdk:init
18
+
19
+ # 3. Edit sdk.config.json, then generate
20
+ bun run gen:sdk
21
+
22
+ # 4. Run the split-by-domain regression checks
23
+ bun run test:gen:sdk
24
+ ```
25
+
26
+ ## Consumer usage after publish
27
+
28
+ ```bash
29
+ # inside an Angular workspace that installed @ojiepermana/angular
30
+ ng generate @ojiepermana/angular:sdk-init
31
+ # edit config/sdk.config.json
32
+ ng generate @ojiepermana/angular:sdk
33
+ ```
34
+
35
+ The main consumer feature is generating an SDK from
36
+ `config/sdk.config.json`. The consumer flow is: initialize the config once,
37
+ edit it, then run `sdk` whenever the OpenAPI source changes.
38
+
39
+ If a consumer wants short script aliases in `package.json`, they can add this
40
+ script block to their workspace:
41
+
42
+ ```json
43
+ {
44
+ "scripts": {
45
+ "gen:sdk:init": "ng generate @ojiepermana/angular:sdk-init",
46
+ "gen:sdk": "ng generate @ojiepermana/angular:sdk"
47
+ }
48
+ }
49
+ ```
50
+
51
+ Consumers do not need a `gen:sdk:build` step. That build command only exists
52
+ for developing this repository, where the schematic source under
53
+ `projects/angular/generator/api` must be compiled before local execution.
54
+
55
+ ## Schematics
56
+
57
+ The entrypoint exposes two schematics, registered in the parent collection at [`projects/angular/collection.json`](../../collection.json):
58
+
59
+ | Schematic | Script | Purpose |
60
+ | ---------- | ---------------------- | ------------------------------------------------ |
61
+ | `sdk-init` | `bun run gen:sdk:init` | Create `config/sdk.config.json` from the example |
62
+ | `sdk` | `bun run gen:sdk` | Run the generator using `config/sdk.config.json` |
63
+
64
+ Both can be invoked directly with `ng generate` too:
65
+
66
+ ```bash
67
+ bunx ng generate ./projects/angular/collection.json:sdk-init [--force] [--path=custom/sdk.config.json]
68
+ bunx ng generate ./projects/angular/collection.json:sdk [--dry-run] [--config=sdk.config.json] [--target=1]
69
+
70
+ # after publish / inside a consuming workspace:
71
+ ng generate @ojiepermana/angular:sdk-init [--force] [--path=custom/sdk.config.json]
72
+ ng generate @ojiepermana/angular:sdk [--dry-run] [--config=sdk.config.json] [--target=1]
73
+ ```
74
+
75
+ ### `init` options
76
+
77
+ | Option | Type | Default | Description |
78
+ | --------- | ------- | ------------------------ | --------------------------------------------- |
79
+ | `--path` | string | `config/sdk.config.json` | Destination path, relative to workspace root. |
80
+ | `--force` | boolean | `false` | Overwrite the file if it already exists. |
81
+
82
+ ### `sdk` options
83
+
84
+ | Option | Type | Default | Description |
85
+ | ----------- | ------ | ------------------------ | ------------------------------------------------------------------ |
86
+ | `--config` | string | `config/sdk.config.json` | Path to the config file, relative to workspace root. |
87
+ | `--target` | string | _(all)_ | Only generate one target. Accepts a 1-based index or `clientName`. |
88
+ | `--dry-run` | flag | — | Preview file operations without writing anything. |
89
+
90
+ ## Config shape
91
+
92
+ ```jsonc
93
+ {
94
+ "$schema": "./node_modules/@ojiepermana/angular/generator/api/schematics/sdk/schema.json",
95
+ "targets": [
96
+ {
97
+ "input": "./openapi.yaml",
98
+ "output": "./sdk",
99
+ "mode": "library", // "standalone" | "library" | "secondary-entrypoint"
100
+ "clientName": "Api",
101
+ "packageName": "@my-scope/sdk", // used in "library" mode
102
+ "packageVersion": "0.0.1", // used in "library" mode
103
+ "rootUrl": "", // optional; empty string means same-origin requests
104
+ "splitByDomain": true, // optional; defaults true for "library", false otherwise
105
+ "splitDepth": "service", // "service" (default) | "tag"
106
+ "features": {
107
+ "models": true,
108
+ "operations": true,
109
+ "services": true,
110
+ "client": true,
111
+ "metadata": true,
112
+ "navigation": true,
113
+ },
114
+ },
115
+ ],
116
+ }
117
+ ```
118
+
119
+ Multiple targets are supported — one config run can emit several SDKs.
120
+
121
+ If `rootUrl` is omitted or left empty, the generated SDK uses same-origin
122
+ requests by default. Consumer apps can override it at runtime with
123
+ `provideApiConfiguration(...)`.
124
+
125
+ ### Runtime base URL
126
+
127
+ The generated SDK does not read `sdk.config.json` at runtime. The value of
128
+ `targets[].rootUrl` is only used during code generation to seed the default
129
+ `ApiConfiguration.rootUrl` value.
130
+
131
+ - `rootUrl: ""` or omitted: requests use the current origin, for example
132
+ `/api/users` on the same host as the Angular app.
133
+ - `rootUrl: "https://api.example.com"`: the generated SDK defaults to that
134
+ absolute backend URL.
135
+ - Runtime override: consumer apps can replace the default by providing a new
136
+ value during bootstrap.
137
+
138
+ Example runtime override in a consumer app:
139
+
140
+ ```ts
141
+ import { bootstrapApplication } from '@angular/platform-browser';
142
+ import { provideHttpClient } from '@angular/common/http';
143
+
144
+ import { AppComponent } from './app/app.component';
145
+ import { provideApiConfiguration } from '@my-scope/sdk';
146
+
147
+ bootstrapApplication(AppComponent, {
148
+ providers: [provideHttpClient(), provideApiConfiguration('https://api.example.com')],
149
+ });
150
+ ```
151
+
152
+ For standalone generated output inside the same workspace, import
153
+ `provideApiConfiguration` from the generated SDK barrel instead of an npm
154
+ package path.
155
+
156
+ ## Per-domain layout
157
+
158
+ By default, standalone and secondary-entrypoint targets emit a flat layout
159
+ (`models/`, `fn/`, `services/`, … all at the output root). `mode: "library"`
160
+ defaults to `splitByDomain: true` so the generated package is split into
161
+ secondary entrypoints immediately. You can still set `splitByDomain: false` if
162
+ you need the older flat library shape. Cross-domain models and client primitives
163
+ land in `shared/`.
164
+
165
+ ```jsonc
166
+ {
167
+ "splitByDomain": true,
168
+ "splitDepth": "service", // or "tag"
169
+ }
170
+ ```
171
+
172
+ `splitDepth` controls granularity. It is only read when `splitByDomain` is
173
+ `true`.
174
+
175
+ | `splitDepth` | Folder strategy | Example (spec with tags `Access/Role`, `Access/Permission`, `Storage/GCS`, `Storage/S3`, `Auth`) |
176
+ | ------------ | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
177
+ | `service` | One folder per **root** tag (each tag's `parent` chain collapses to its root). One folder per backend service. | `access/` (holds Role + Permission + Role-Permission + …), `storage/` (holds GCS + S3), `auth/`, `shared/`, root `public-api.ts` |
178
+ | `tag` | One folder per **leaf** tag, nested under the parent chain. Keeps fine-grained separation while staying grouped. | `access/role/`, `access/permission/`, `access/role-permission/`, `storage/gcs/`, `storage/s3/`, `auth/`, `shared/`, root `public-api.ts` |
179
+
180
+ Every domain folder contains `services/`, `fn/`, `models/`, `permissions/`,
181
+ and its own `public-api.ts`. The root still owns the aggregate metadata barrel:
182
+ `metadata.ts`, `openapi-helpers.ts`, and `permissions/index.ts` stay at the SDK
183
+ root so `shared/` never depends on sibling domains. In standalone and
184
+ secondary-entrypoint modes, the root `public-api.ts` aggregates `shared`, root
185
+ metadata helpers, and every domain for convenience. In library mode, domain
186
+ exports stay in their secondary entrypoints so consumers deep import the domain
187
+ they need.
188
+
189
+ Model ownership rule (per-domain mode):
190
+
191
+ - A model used by exactly one domain → emitted inside that domain's `models/`.
192
+ - A model shared across two or more domains → emitted inside `shared/models/`.
193
+ - Client primitives (`ApiConfiguration`, `BaseService`, `RequestBuilder`,
194
+ `StrictHttpResponse`, `Api`), shared metadata types, validators, and
195
+ navigation always live under `shared/`.
196
+ - Aggregate metadata helpers (`metadata.ts`, `openapi-helpers.ts`) and the
197
+ top-level `permissions/index.ts` stay at the SDK root.
198
+
199
+ Example consumption when using `mode: 'library'`:
200
+
201
+ ```ts
202
+ import { RoleService } from '@my-scope/sdk/access';
203
+ import { ApprovalInstanceService, SubmitRequest } from '@my-scope/sdk/approval';
204
+ import { GCSService } from '@my-scope/sdk/storage'; // splitDepth: 'service'
205
+ import { GCSService } from '@my-scope/sdk/storage/gcs'; // splitDepth: 'tag'
206
+ ```
207
+
208
+ ## Output modes
209
+
210
+ | Mode | What it emits | Use when… |
211
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------- |
212
+ | `standalone` | A plain folder (no `ng-package.json`). | You consume the SDK via path alias / `tsconfig.paths` inside the same app. |
213
+ | `library` | Split-by-domain output plus package metadata and nested `ng-package.json` manifests for secondary entrypoints. | You want a buildable/publishable Angular package with efficient deep imports. |
214
+ | `secondary-entrypoint` | Standalone output **plus** a minimal `ng-package.json` pointing at `public-api.ts`, plus nested `ng-package.json` files for split-by-domain secondary entrypoints. | You drop the folder inside an existing library so ng-packagr picks it up as a subpath. |
215
+
216
+ In `library` mode, output also includes `tsconfig.lib.json` and `tsconfig.lib.prod.json`.
217
+ `ng-package.dest` defaults to `dist/<output-folder-name>`.
218
+
219
+ ## Feature flags
220
+
221
+ All default to `true`. Turn off anything you don't need to shrink the output.
222
+
223
+ | Flag | Emits |
224
+ | ------------ | ------------------------------------------------------------------------------------------ |
225
+ | `models` | `models/*.ts` — flat interfaces, enum aliases, array aliases. |
226
+ | `operations` | `fn/<tag>/<operation-id>.ts` — tree-shakeable request functions with `.PATH`. |
227
+ | `services` | `services/<tag>.service.ts` — `@Injectable({providedIn:'root'})` wrappers. |
228
+ | `client` | `api-configuration.ts`, `base-service.ts`, `request-builder.ts`, `api.ts`. |
229
+ | `metadata` | `permissions/*`, `validators/*`, `metadata.ts`, `openapi-helpers.ts`. |
230
+ | `navigation` | `api.navigation.ts` — `NavigationItem[]` ready for `NavigationService.registerItems(...)`. |
231
+
232
+ ## Pipeline
233
+
234
+ ```text
235
+ sdk.config.json → loader → spec (YAML/JSON) → IR → emitters → writer → Angular CLI Tree
236
+ ```
237
+
238
+ - `src/config/` — config schema + loader (supports JSONC and `.js`/`.cjs`).
239
+ - `src/parser/` — OpenAPI → intermediate representation.
240
+ - `src/emit/` — one module per output concern (models, operations, services, client, metadata, navigation, public-api).
241
+ - `src/layout/` — post-emit layout transforms (e.g. `splitByDomain` reorganisation).
242
+ - `src/writer/` — mode wrappers (standalone / library / secondary entrypoint).
243
+ - `public-api.ts` — published TypeScript entrypoint for `@ojiepermana/angular/generator/api`.
244
+ - `schematics/init/` — creates `sdk.config.json` from the example template.
245
+ - `schematics/sdk/` — orchestrates engine and writes virtual files into the CLI `Tree`.
246
+
247
+ ## Generated runtime conventions
248
+
249
+ - Tree-shakeable: `import { listUsers } from './sdk/fn/user/list-users'` pulls only one HTTP call.
250
+ - Services: every operation gets `op()` (body `Observable<T>`) and `op$Response()` (full `StrictHttpResponse<T>`).
251
+ - `RequestBuilder` is intentionally minimal — no `style`/`explode` logic — to keep the output lightweight.
252
+ - All files carry a `DO NOT EDIT` banner and `/* eslint-disable */`.
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Public config shape for the SDK generator.
3
+ *
4
+ * Users place an `sdk.config.json` at the workspace root describing one or more
5
+ * generation targets. All paths are resolved relative to the workspace root
6
+ * (i.e. the directory containing the config file).
7
+ */
8
+ const DEFAULT_BANNER = '/* eslint-disable */\n/* Auto-generated by @ojiepermana/angular/generator/api. DO NOT EDIT. */';
9
+ const DEFAULT_FEATURES = {
10
+ models: true,
11
+ operations: true,
12
+ services: true,
13
+ client: true,
14
+ metadata: true,
15
+ navigation: true,
16
+ };
17
+ function resolveTarget(raw) {
18
+ if (!raw || typeof raw !== 'object') {
19
+ throw new Error('Invalid target: expected object');
20
+ }
21
+ if (!raw.input)
22
+ throw new Error('Target is missing required "input"');
23
+ if (!raw.output)
24
+ throw new Error('Target is missing required "output"');
25
+ const mode = raw.mode ?? 'standalone';
26
+ if (!['standalone', 'library', 'secondary-entrypoint'].includes(mode)) {
27
+ throw new Error(`Invalid target mode: ${mode}`);
28
+ }
29
+ const splitByDomain = raw.splitByDomain ?? mode === 'library';
30
+ return {
31
+ input: raw.input,
32
+ output: raw.output,
33
+ mode,
34
+ clientName: raw.clientName ?? 'Api',
35
+ packageName: raw.packageName ?? '@local/sdk',
36
+ packageVersion: raw.packageVersion ?? '0.0.1',
37
+ rootUrl: raw.rootUrl,
38
+ features: { ...DEFAULT_FEATURES, ...(raw.features ?? {}) },
39
+ splitByDomain,
40
+ splitDepth: raw.splitDepth === 'tag' ? 'tag' : 'service',
41
+ banner: raw.banner ?? DEFAULT_BANNER,
42
+ };
43
+ }
44
+ function resolveConfig(raw) {
45
+ if (!raw || typeof raw !== 'object') {
46
+ throw new Error('Invalid SDK config: root must be an object');
47
+ }
48
+ const cfg = raw;
49
+ if (!Array.isArray(cfg.targets) || cfg.targets.length === 0) {
50
+ throw new Error('Invalid SDK config: "targets" must be a non-empty array');
51
+ }
52
+ return cfg.targets.map(resolveTarget);
53
+ }
54
+
55
+ /*
56
+ * Public API Surface of @ojiepermana/angular-sdk
57
+ * (also re-exported as the secondary entrypoint @ojiepermana/angular/sdk)
58
+ *
59
+ * This package is primarily consumed as an Angular schematic collection
60
+ * (`init` and `sdk`). The TypeScript surface intentionally stays small and
61
+ * Node-free so it can be published as a standalone Angular library entry point.
62
+ */
63
+
64
+ /**
65
+ * Generated bundle index. Do not edit.
66
+ */
67
+
68
+ export { resolveConfig, resolveTarget };
69
+ //# sourceMappingURL=ojiepermana-angular-sdk.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ojiepermana-angular-sdk.mjs","sources":["../../../library/sdk/src/config/schema.ts","../../../library/sdk/public-api.ts","../../../library/sdk/ojiepermana-angular-sdk.ts"],"sourcesContent":["/**\n * Public config shape for the SDK generator.\n *\n * Users place an `sdk.config.json` at the workspace root describing one or more\n * generation targets. All paths are resolved relative to the workspace root\n * (i.e. the directory containing the config file).\n */\n\nexport type SdkOutputMode = 'standalone' | 'library' | 'secondary-entrypoint';\n\nexport interface SdkFeatureFlags {\n /** Emit `models/*.ts` (type-only DTO interfaces). Default `true`. */\n models?: boolean;\n /** Emit tree-shakeable operation functions in `fn/<tag>/*.ts`. Default `true`. */\n operations?: boolean;\n /** Emit grouped Injectable service classes per tag. Default `true`. */\n services?: boolean;\n /** Emit the runtime client primitives (ApiConfiguration, BaseService, etc). Default `true`. */\n client?: boolean;\n /** Emit operation rules + field validators + permission helpers. Default `true`. */\n metadata?: boolean;\n /** Emit navigation tree derived from tags (parent, x-icon). Default `false`. */\n navigation?: boolean;\n}\n\nexport interface SdkTargetConfig {\n /** Path to OpenAPI 3.x spec (YAML or JSON). Required. */\n input: string;\n /** Output directory (relative to workspace root). Required. */\n output: string;\n /** Output mode. Defaults to `\"standalone\"`. */\n mode?: SdkOutputMode;\n /** Optional human-readable name used for logs & the generated `Api` class. */\n clientName?: string;\n /** Package name used when `mode === \"library\"`. */\n packageName?: string;\n /** Package version used when `mode === \"library\"`. Defaults to `0.0.1`. */\n packageVersion?: string;\n /** Default rootUrl baked into ApiConfiguration. Defaults to an empty string for same-origin requests. */\n rootUrl?: string;\n /** Feature toggles. Every feature defaults to `true` except `navigation` (default `true` too). */\n features?: SdkFeatureFlags;\n /**\n * When `true`, reorganize emitted files into one folder per domain (derived\n * from OpenAPI tags). Models shared by multiple domains live in `shared/`,\n * domain-owned models live inside each domain. Defaults to `true` for\n * `mode: \"library\"` and `false` otherwise.\n */\n splitByDomain?: boolean;\n /**\n * Granularity of `splitByDomain`. Only meaningful when `splitByDomain` is\n * `true`. `'service'` (default) groups every tag under its root parent — one\n * folder per backend service (e.g. all Role/Permission/... tags collapse into\n * `access/`). `'tag'` emits one folder per leaf tag, nested under the parent\n * chain (e.g. `storage/gcs/`, `storage/s3/`, `access/role/`).\n */\n splitDepth?: 'service' | 'tag';\n /** Custom file banner. Defaults to a short auto-generated notice. */\n banner?: string;\n}\n\nexport interface SdkConfig {\n targets: SdkTargetConfig[];\n}\n\nexport interface ResolvedFeatureFlags {\n models: boolean;\n operations: boolean;\n services: boolean;\n client: boolean;\n metadata: boolean;\n navigation: boolean;\n}\n\nexport interface ResolvedSdkTarget {\n input: string;\n output: string;\n mode: SdkOutputMode;\n clientName: string;\n packageName: string;\n packageVersion: string;\n rootUrl: string | undefined;\n features: ResolvedFeatureFlags;\n splitByDomain: boolean;\n splitDepth: 'service' | 'tag';\n banner: string;\n}\n\nconst DEFAULT_BANNER = '/* eslint-disable */\\n/* Auto-generated by @ojiepermana/angular/generator/api. DO NOT EDIT. */';\n\nconst DEFAULT_FEATURES: ResolvedFeatureFlags = {\n models: true,\n operations: true,\n services: true,\n client: true,\n metadata: true,\n navigation: true,\n};\n\nexport function resolveTarget(raw: SdkTargetConfig): ResolvedSdkTarget {\n if (!raw || typeof raw !== 'object') {\n throw new Error('Invalid target: expected object');\n }\n if (!raw.input) throw new Error('Target is missing required \"input\"');\n if (!raw.output) throw new Error('Target is missing required \"output\"');\n\n const mode: SdkOutputMode = raw.mode ?? 'standalone';\n if (!['standalone', 'library', 'secondary-entrypoint'].includes(mode)) {\n throw new Error(`Invalid target mode: ${mode}`);\n }\n\n const splitByDomain = raw.splitByDomain ?? mode === 'library';\n\n return {\n input: raw.input,\n output: raw.output,\n mode,\n clientName: raw.clientName ?? 'Api',\n packageName: raw.packageName ?? '@local/sdk',\n packageVersion: raw.packageVersion ?? '0.0.1',\n rootUrl: raw.rootUrl,\n features: { ...DEFAULT_FEATURES, ...(raw.features ?? {}) },\n splitByDomain,\n splitDepth: raw.splitDepth === 'tag' ? 'tag' : 'service',\n banner: raw.banner ?? DEFAULT_BANNER,\n };\n}\n\nexport function resolveConfig(raw: unknown): ResolvedSdkTarget[] {\n if (!raw || typeof raw !== 'object') {\n throw new Error('Invalid SDK config: root must be an object');\n }\n const cfg = raw as SdkConfig;\n if (!Array.isArray(cfg.targets) || cfg.targets.length === 0) {\n throw new Error('Invalid SDK config: \"targets\" must be a non-empty array');\n }\n return cfg.targets.map(resolveTarget);\n}\n","/*\n * Public API Surface of @ojiepermana/angular-sdk\n * (also re-exported as the secondary entrypoint @ojiepermana/angular/sdk)\n *\n * This package is primarily consumed as an Angular schematic collection\n * (`init` and `sdk`). The TypeScript surface intentionally stays small and\n * Node-free so it can be published as a standalone Angular library entry point.\n */\n\nexport type {\n ResolvedFeatureFlags,\n ResolvedSdkTarget,\n SdkConfig,\n SdkFeatureFlags,\n SdkOutputMode,\n SdkTargetConfig,\n} from './src/config/schema';\nexport { resolveConfig, resolveTarget } from './src/config/schema';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;;;;;AAMG;AAkFH,MAAM,cAAc,GAAG,gGAAgG;AAEvH,MAAM,gBAAgB,GAAyB;AAC7C,IAAA,MAAM,EAAE,IAAI;AACZ,IAAA,UAAU,EAAE,IAAI;AAChB,IAAA,QAAQ,EAAE,IAAI;AACd,IAAA,MAAM,EAAE,IAAI;AACZ,IAAA,QAAQ,EAAE,IAAI;AACd,IAAA,UAAU,EAAE,IAAI;CACjB;AAEK,SAAU,aAAa,CAAC,GAAoB,EAAA;IAChD,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AACnC,QAAA,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC;IACpD;IACA,IAAI,CAAC,GAAG,CAAC,KAAK;AAAE,QAAA,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC;IACrE,IAAI,CAAC,GAAG,CAAC,MAAM;AAAE,QAAA,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC;AAEvE,IAAA,MAAM,IAAI,GAAkB,GAAG,CAAC,IAAI,IAAI,YAAY;AACpD,IAAA,IAAI,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,sBAAsB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AACrE,QAAA,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAA,CAAE,CAAC;IACjD;IAEA,MAAM,aAAa,GAAG,GAAG,CAAC,aAAa,IAAI,IAAI,KAAK,SAAS;IAE7D,OAAO;QACL,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,IAAI;AACJ,QAAA,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,KAAK;AACnC,QAAA,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,YAAY;AAC5C,QAAA,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,OAAO;QAC7C,OAAO,EAAE,GAAG,CAAC,OAAO;AACpB,QAAA,QAAQ,EAAE,EAAE,GAAG,gBAAgB,EAAE,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE;QAC1D,aAAa;AACb,QAAA,UAAU,EAAE,GAAG,CAAC,UAAU,KAAK,KAAK,GAAG,KAAK,GAAG,SAAS;AACxD,QAAA,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,cAAc;KACrC;AACH;AAEM,SAAU,aAAa,CAAC,GAAY,EAAA;IACxC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AACnC,QAAA,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC;IAC/D;IACA,MAAM,GAAG,GAAG,GAAgB;AAC5B,IAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;AAC3D,QAAA,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC;IAC5E;IACA,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;AACvC;;ACzIA;;;;;;;AAOG;;ACPH;;AAEG;;;;"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@ojiepermana/angular-sdk",
3
+ "version": "22.0.27",
4
+ "description": "OpenAPI 3.x → Angular SDK generator (schematics + config surface) for @ojiepermana/angular.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/edsis/angular.git"
8
+ },
9
+ "homepage": "https://github.com/edsis/angular#readme",
10
+ "bugs": {
11
+ "url": "https://github.com/edsis/angular/issues"
12
+ },
13
+ "peerDependencies": {
14
+ "@angular/common": ">=22.0.0",
15
+ "@angular/core": ">=22.0.0"
16
+ },
17
+ "dependencies": {
18
+ "tslib": "^2.8.1"
19
+ },
20
+ "publishConfig": {
21
+ "access": "public",
22
+ "registry": "https://registry.npmjs.org/"
23
+ },
24
+ "sideEffects": false,
25
+ "module": "fesm2022/ojiepermana-angular-sdk.mjs",
26
+ "typings": "types/ojiepermana-angular-sdk.d.ts",
27
+ "exports": {
28
+ "./package.json": {
29
+ "default": "./package.json"
30
+ },
31
+ ".": {
32
+ "types": "./types/ojiepermana-angular-sdk.d.ts",
33
+ "default": "./fesm2022/ojiepermana-angular-sdk.mjs"
34
+ }
35
+ },
36
+ "type": "module"
37
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Public config shape for the SDK generator.
3
+ *
4
+ * Users place an `sdk.config.json` at the workspace root describing one or more
5
+ * generation targets. All paths are resolved relative to the workspace root
6
+ * (i.e. the directory containing the config file).
7
+ */
8
+ type SdkOutputMode = 'standalone' | 'library' | 'secondary-entrypoint';
9
+ interface SdkFeatureFlags {
10
+ /** Emit `models/*.ts` (type-only DTO interfaces). Default `true`. */
11
+ models?: boolean;
12
+ /** Emit tree-shakeable operation functions in `fn/<tag>/*.ts`. Default `true`. */
13
+ operations?: boolean;
14
+ /** Emit grouped Injectable service classes per tag. Default `true`. */
15
+ services?: boolean;
16
+ /** Emit the runtime client primitives (ApiConfiguration, BaseService, etc). Default `true`. */
17
+ client?: boolean;
18
+ /** Emit operation rules + field validators + permission helpers. Default `true`. */
19
+ metadata?: boolean;
20
+ /** Emit navigation tree derived from tags (parent, x-icon). Default `false`. */
21
+ navigation?: boolean;
22
+ }
23
+ interface SdkTargetConfig {
24
+ /** Path to OpenAPI 3.x spec (YAML or JSON). Required. */
25
+ input: string;
26
+ /** Output directory (relative to workspace root). Required. */
27
+ output: string;
28
+ /** Output mode. Defaults to `"standalone"`. */
29
+ mode?: SdkOutputMode;
30
+ /** Optional human-readable name used for logs & the generated `Api` class. */
31
+ clientName?: string;
32
+ /** Package name used when `mode === "library"`. */
33
+ packageName?: string;
34
+ /** Package version used when `mode === "library"`. Defaults to `0.0.1`. */
35
+ packageVersion?: string;
36
+ /** Default rootUrl baked into ApiConfiguration. Defaults to an empty string for same-origin requests. */
37
+ rootUrl?: string;
38
+ /** Feature toggles. Every feature defaults to `true` except `navigation` (default `true` too). */
39
+ features?: SdkFeatureFlags;
40
+ /**
41
+ * When `true`, reorganize emitted files into one folder per domain (derived
42
+ * from OpenAPI tags). Models shared by multiple domains live in `shared/`,
43
+ * domain-owned models live inside each domain. Defaults to `true` for
44
+ * `mode: "library"` and `false` otherwise.
45
+ */
46
+ splitByDomain?: boolean;
47
+ /**
48
+ * Granularity of `splitByDomain`. Only meaningful when `splitByDomain` is
49
+ * `true`. `'service'` (default) groups every tag under its root parent — one
50
+ * folder per backend service (e.g. all Role/Permission/... tags collapse into
51
+ * `access/`). `'tag'` emits one folder per leaf tag, nested under the parent
52
+ * chain (e.g. `storage/gcs/`, `storage/s3/`, `access/role/`).
53
+ */
54
+ splitDepth?: 'service' | 'tag';
55
+ /** Custom file banner. Defaults to a short auto-generated notice. */
56
+ banner?: string;
57
+ }
58
+ interface SdkConfig {
59
+ targets: SdkTargetConfig[];
60
+ }
61
+ interface ResolvedFeatureFlags {
62
+ models: boolean;
63
+ operations: boolean;
64
+ services: boolean;
65
+ client: boolean;
66
+ metadata: boolean;
67
+ navigation: boolean;
68
+ }
69
+ interface ResolvedSdkTarget {
70
+ input: string;
71
+ output: string;
72
+ mode: SdkOutputMode;
73
+ clientName: string;
74
+ packageName: string;
75
+ packageVersion: string;
76
+ rootUrl: string | undefined;
77
+ features: ResolvedFeatureFlags;
78
+ splitByDomain: boolean;
79
+ splitDepth: 'service' | 'tag';
80
+ banner: string;
81
+ }
82
+ declare function resolveTarget(raw: SdkTargetConfig): ResolvedSdkTarget;
83
+ declare function resolveConfig(raw: unknown): ResolvedSdkTarget[];
84
+
85
+ export { resolveConfig, resolveTarget };
86
+ export type { ResolvedFeatureFlags, ResolvedSdkTarget, SdkConfig, SdkFeatureFlags, SdkOutputMode, SdkTargetConfig };