@gooddata/create-pluggable-module 11.40.0-alpha.3
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 +59 -0
- package/dist/templates/harness/.env.template +9 -0
- package/dist/templates/harness/.gitignore +10 -0
- package/dist/templates/harness/README.md +45 -0
- package/dist/templates/harness/eslint.config.ts +3 -0
- package/dist/templates/harness/index.html +13 -0
- package/dist/templates/harness/package.json +70 -0
- package/dist/templates/harness/src/app.tsx +81 -0
- package/dist/templates/harness/tsconfig.json +70 -0
- package/dist/templates/harness/typings.d.ts +13 -0
- package/dist/templates/harness/vite.config.ts +111 -0
- package/dist/templates/module/.gitignore +11 -0
- package/dist/templates/module/README.md +35 -0
- package/dist/templates/module/eslint.config.ts +3 -0
- package/dist/templates/module/package.json +84 -0
- package/dist/templates/module/src/App.test.tsx +53 -0
- package/dist/templates/module/src/App.tsx +34 -0
- package/dist/templates/module/src/AppProviders.tsx +26 -0
- package/dist/templates/module/src/index.ts +3 -0
- package/dist/templates/module/src/pluggableApp.tsx +56 -0
- package/dist/templates/module/src/translations/de-DE.json +6 -0
- package/dist/templates/module/src/translations/en-AU.json +6 -0
- package/dist/templates/module/src/translations/en-GB.json +6 -0
- package/dist/templates/module/src/translations/en-US.json +6 -0
- package/dist/templates/module/src/translations/es-419.json +6 -0
- package/dist/templates/module/src/translations/es-ES.json +6 -0
- package/dist/templates/module/src/translations/fi-FI.json +6 -0
- package/dist/templates/module/src/translations/fr-CA.json +6 -0
- package/dist/templates/module/src/translations/fr-FR.json +6 -0
- package/dist/templates/module/src/translations/id-ID.json +6 -0
- package/dist/templates/module/src/translations/it-IT.json +6 -0
- package/dist/templates/module/src/translations/ja-JP.json +6 -0
- package/dist/templates/module/src/translations/ko-KR.json +6 -0
- package/dist/templates/module/src/translations/nl-NL.json +6 -0
- package/dist/templates/module/src/translations/pl-PL.json +6 -0
- package/dist/templates/module/src/translations/pt-BR.json +6 -0
- package/dist/templates/module/src/translations/pt-PT.json +6 -0
- package/dist/templates/module/src/translations/ru-RU.json +6 -0
- package/dist/templates/module/src/translations/sl-SI.json +6 -0
- package/dist/templates/module/src/translations/th-TH.json +6 -0
- package/dist/templates/module/src/translations/tr-TR.json +6 -0
- package/dist/templates/module/src/translations/translations.ts +71 -0
- package/dist/templates/module/src/translations/uk-UA.json +6 -0
- package/dist/templates/module/src/translations/vi-VN.json +6 -0
- package/dist/templates/module/src/translations/zh-HK.json +6 -0
- package/dist/templates/module/src/translations/zh-Hans.json +6 -0
- package/dist/templates/module/src/translations/zh-Hant.json +6 -0
- package/dist/templates/module/tsconfig.json +65 -0
- package/dist/templates/module/vite.config.ts +140 -0
- package/dist/templates/module/vitest.config.ts +12 -0
- package/esm/engine/__tests__/anchors.test.d.ts +1 -0
- package/esm/engine/__tests__/anchors.test.js +44 -0
- package/esm/engine/__tests__/copyTemplate.test.d.ts +1 -0
- package/esm/engine/__tests__/copyTemplate.test.js +59 -0
- package/esm/engine/__tests__/derived.test.d.ts +1 -0
- package/esm/engine/__tests__/derived.test.js +30 -0
- package/esm/engine/__tests__/jsonAnchors.test.d.ts +1 -0
- package/esm/engine/__tests__/jsonAnchors.test.js +52 -0
- package/esm/engine/__tests__/repoDetection.test.d.ts +1 -0
- package/esm/engine/__tests__/repoDetection.test.js +63 -0
- package/esm/engine/__tests__/scrubPackageJsonVersions.d.ts +1 -0
- package/esm/engine/__tests__/scrubPackageJsonVersions.js +34 -0
- package/esm/engine/__tests__/scrubPackageJsonVersions.test.d.ts +1 -0
- package/esm/engine/__tests__/scrubPackageJsonVersions.test.js +79 -0
- package/esm/engine/__tests__/snapshot.test.d.ts +1 -0
- package/esm/engine/__tests__/snapshot.test.js +93 -0
- package/esm/engine/anchors.d.ts +17 -0
- package/esm/engine/anchors.js +43 -0
- package/esm/engine/checkAnchors.d.ts +12 -0
- package/esm/engine/checkAnchors.js +44 -0
- package/esm/engine/copyTemplate.d.ts +11 -0
- package/esm/engine/copyTemplate.js +70 -0
- package/esm/engine/derived.d.ts +32 -0
- package/esm/engine/derived.js +85 -0
- package/esm/engine/jsonAnchors.d.ts +13 -0
- package/esm/engine/jsonAnchors.js +42 -0
- package/esm/engine/prompts.d.ts +15 -0
- package/esm/engine/prompts.js +157 -0
- package/esm/engine/repoDetection.d.ts +18 -0
- package/esm/engine/repoDetection.js +47 -0
- package/esm/engine/runProfile.d.ts +18 -0
- package/esm/engine/runProfile.js +179 -0
- package/esm/engine/spawn.d.ts +13 -0
- package/esm/engine/spawn.js +30 -0
- package/esm/index.d.ts +10 -0
- package/esm/index.js +62 -0
- package/esm/profiles/__tests__/client.test.d.ts +1 -0
- package/esm/profiles/__tests__/client.test.js +151 -0
- package/esm/profiles/client.d.ts +2 -0
- package/esm/profiles/client.js +208 -0
- package/esm/types.d.ts +194 -0
- package/esm/types.js +2 -0
- package/package.json +77 -0
package/esm/types.d.ts
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contracts shared between the engine (engine/runProfile.ts and friends) and the
|
|
3
|
+
* profile authors (profiles/client.ts, profiles/internal.ts). The engine drives
|
|
4
|
+
* the *order* of operations (prompt → derive → copy → register → postCopy); the
|
|
5
|
+
* profile fills in *what* each step does.
|
|
6
|
+
*
|
|
7
|
+
* The IScaffoldProfile interface is small on purpose: a new profile is a
|
|
8
|
+
* single file that fills in these fields, and diffing two profiles tells you
|
|
9
|
+
* exactly how they diverge.
|
|
10
|
+
*/
|
|
11
|
+
export type ProfileName = "client" | "internal";
|
|
12
|
+
export type ApplicationScope = "workspace" | "organization";
|
|
13
|
+
export type PackageManager = "npm" | "yarn" | "pnpm" | "rush";
|
|
14
|
+
/**
|
|
15
|
+
* Output of engine/repoDetection.ts. Computed once at startup from `cwd`,
|
|
16
|
+
* then threaded through the rest of the pipeline so neither profile nor
|
|
17
|
+
* registrations need to redo filesystem probes.
|
|
18
|
+
*
|
|
19
|
+
* Profiles that need to gate on "is this a Rush monorepo" check
|
|
20
|
+
* `packageManager === "rush"` — there's no separate boolean to keep in sync.
|
|
21
|
+
*/
|
|
22
|
+
export interface IRepoInfo {
|
|
23
|
+
/** Absolute path resolved from process.cwd(). */
|
|
24
|
+
repoRoot: string;
|
|
25
|
+
/** Detected package manager — drives postCopy. */
|
|
26
|
+
packageManager: PackageManager;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Answers populated by the engine via the shared prompts (appName, title, scope).
|
|
30
|
+
* Profile-specific extra prompts (e.g. `maintainer` for internal, `destPath` for
|
|
31
|
+
* client) write into the same object under their declared `key`.
|
|
32
|
+
*
|
|
33
|
+
* The index signature is intentional — profiles narrow with a local cast in
|
|
34
|
+
* their callbacks since they know which extras they registered. Trying to make
|
|
35
|
+
* this a discriminated union forces a generic parameter through the whole
|
|
36
|
+
* engine for very little safety gain at this scale.
|
|
37
|
+
*/
|
|
38
|
+
export interface IScaffoldAnswers {
|
|
39
|
+
appName: string;
|
|
40
|
+
title: string;
|
|
41
|
+
scope: ApplicationScope;
|
|
42
|
+
[extraKey: string]: string | undefined;
|
|
43
|
+
}
|
|
44
|
+
export interface IPromptDescriptor {
|
|
45
|
+
/** Key under which the answer lands in IScaffoldAnswers. */
|
|
46
|
+
key: string;
|
|
47
|
+
/** Question text shown via readline. The engine appends ": ". */
|
|
48
|
+
label: string;
|
|
49
|
+
/**
|
|
50
|
+
* Whether an empty answer is accepted (true) or re-prompts the user (false, default).
|
|
51
|
+
* When optional, the answer slot is left undefined; profile callbacks must handle that.
|
|
52
|
+
*/
|
|
53
|
+
optional?: boolean;
|
|
54
|
+
/** Returns null on success, or an error string to display and re-prompt. */
|
|
55
|
+
validate?: (value: string) => string | null;
|
|
56
|
+
}
|
|
57
|
+
export interface IDerivedValues {
|
|
58
|
+
/** Default route under which the host mounts the app, e.g. "/foo" for gdc-foo. */
|
|
59
|
+
route: string;
|
|
60
|
+
/** Module Federation `name` — a valid JS identifier derived from appName. */
|
|
61
|
+
federationName: string;
|
|
62
|
+
/** Compile-time env var the host/harness reads to override the dev remoteEntry URL. */
|
|
63
|
+
remoteUrlEnvVar: string;
|
|
64
|
+
/** Port the harness vite dev server listens on. */
|
|
65
|
+
devPort: number;
|
|
66
|
+
/** Port the module federation preview server listens on (= devPort + 100). */
|
|
67
|
+
moduleDevPort: number;
|
|
68
|
+
/** Position in the host menu among apps of the same scope. */
|
|
69
|
+
menuOrder: number;
|
|
70
|
+
}
|
|
71
|
+
export interface IProfileContext {
|
|
72
|
+
answers: IScaffoldAnswers;
|
|
73
|
+
derived: IDerivedValues;
|
|
74
|
+
/** Absolute path to the repo the engine is scaffolding into. */
|
|
75
|
+
repoRoot: string;
|
|
76
|
+
/** Absolute destination root for the new module, e.g. <repoRoot>/modules/<appName>/. */
|
|
77
|
+
destRoot: string;
|
|
78
|
+
/** Detected package manager — drives postCopy. */
|
|
79
|
+
packageManager: PackageManager;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Ordered list of token → replacement pairs applied to every text file in a
|
|
83
|
+
* template subtree. ORDER MATTERS:
|
|
84
|
+
* - longer tokens MUST come before shorter ones that are their substrings
|
|
85
|
+
* (e.g. `gdc-app-template-module` before `gdc-app-template`),
|
|
86
|
+
* - we use an array (not Record<string, string>) so JS-engine integer-key
|
|
87
|
+
* iteration ordering can't reshuffle numeric tokens (`"8450"`, `"8550"`)
|
|
88
|
+
* ahead of string tokens.
|
|
89
|
+
*/
|
|
90
|
+
export type TokenReplacements = ReadonlyArray<readonly [string, string]>;
|
|
91
|
+
/**
|
|
92
|
+
* A single anchor-driven insertion into an existing repo file. The `emit`
|
|
93
|
+
* callback returns the literal lines (without trailing newlines); the engine
|
|
94
|
+
* splices them in before the line containing PLUGGABLE_APP_SCAFFOLD_ANCHOR
|
|
95
|
+
* (suffixed if `suffix` is set).
|
|
96
|
+
*
|
|
97
|
+
* `preInsertTransform` runs against the file content BEFORE the splice — used
|
|
98
|
+
* by JSONC files (rush.json) to add a trailing comma to the last existing
|
|
99
|
+
* project entry so the spliced array remains valid JSON.
|
|
100
|
+
*/
|
|
101
|
+
export interface IRegistrationStep {
|
|
102
|
+
/** Path relative to repoRoot. */
|
|
103
|
+
file: string;
|
|
104
|
+
/**
|
|
105
|
+
* Disambiguating suffix when a file carries more than one anchor point
|
|
106
|
+
* (e.g. Dockerfile has both `(stages)` and `(remotes)` anchors).
|
|
107
|
+
*/
|
|
108
|
+
suffix?: string;
|
|
109
|
+
preInsertTransform?: (content: string, suffix: string | undefined) => string;
|
|
110
|
+
emit: (ctx: IProfileContext) => string[];
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Additional file tree layered on top of the scaffolded templateSubtrees. Used
|
|
114
|
+
* by profiles that need files which shouldn't live in the shared template —
|
|
115
|
+
* e.g. internal-only deploy configs that would leak GoodData infra if shipped
|
|
116
|
+
* to client repos. Profile authors point `srcDir` at their own bundled assets
|
|
117
|
+
* (typically next to the profile's own source file) so the files physically
|
|
118
|
+
* cannot reach the published template tarball.
|
|
119
|
+
*
|
|
120
|
+
* Token substitution applies the same as for `templateSubtrees`. Overlay files
|
|
121
|
+
* with the same path as a template file overwrite the template version.
|
|
122
|
+
*/
|
|
123
|
+
export interface IOverlayPath {
|
|
124
|
+
/** Absolute path to a directory whose contents are copied into destRoot/destSubdir. */
|
|
125
|
+
srcDir: string;
|
|
126
|
+
/** Subdirectory under destRoot where the overlay contents land (e.g. "harness"). */
|
|
127
|
+
destSubdir: string;
|
|
128
|
+
}
|
|
129
|
+
export interface IScaffoldProfile {
|
|
130
|
+
readonly name: ProfileName;
|
|
131
|
+
/** Prompts displayed after the shared appName/title/scope prompts, in array order. */
|
|
132
|
+
readonly extraPrompts: readonly IPromptDescriptor[];
|
|
133
|
+
/** Resolves where the scaffolded files will land. Receives raw cwd, not repoRoot. */
|
|
134
|
+
resolveDestRoot(answers: IScaffoldAnswers, cwd: string): string;
|
|
135
|
+
/**
|
|
136
|
+
* Subdirectory names under src/templates/ that this profile wants copied into destRoot.
|
|
137
|
+
* Engine copies them in array order, so put `module` before `harness` if harness imports module.
|
|
138
|
+
*/
|
|
139
|
+
readonly templateSubtrees: readonly string[];
|
|
140
|
+
/**
|
|
141
|
+
* Optional override: explicit absolute filesystem paths for each subtree.
|
|
142
|
+
* When set, the engine uses these directly and skips its own resolution.
|
|
143
|
+
* Profile authors use this for internal-only profiles where the templates
|
|
144
|
+
* aren't installed as transitive deps of @gooddata/create-pluggable-module —
|
|
145
|
+
* e.g. gdc-ui's internal scaffolder resolves the workspace templates via
|
|
146
|
+
* its own `import.meta.url`-relative path.
|
|
147
|
+
*
|
|
148
|
+
* Keys must be a superset of `templateSubtrees`. Subtrees without an entry
|
|
149
|
+
* here fall back to the bundled `dist/templates/<subtree>/` (created by
|
|
150
|
+
* prepack-bundle-template.sh). If neither is available, the engine throws.
|
|
151
|
+
*/
|
|
152
|
+
readonly templateSubtreeRoots?: Readonly<Record<string, string>>;
|
|
153
|
+
/**
|
|
154
|
+
* Optional overlays applied after `templateSubtrees`. See `IOverlayPath`.
|
|
155
|
+
* Profile authors use this to keep profile-specific files out of the shared
|
|
156
|
+
* template (which would otherwise leak them at publish time).
|
|
157
|
+
*/
|
|
158
|
+
readonly overlayPaths?: readonly IOverlayPath[];
|
|
159
|
+
/**
|
|
160
|
+
* When true, the engine resolves templates from the workspace source (with
|
|
161
|
+
* workspace-extending tsconfigs etc.) instead of the bundled `dist/templates/`
|
|
162
|
+
* (with inlined tsconfigs). Set true for internal-only profiles that scaffold
|
|
163
|
+
* into a repo that already has the workspace tsconfigs at the expected paths
|
|
164
|
+
* (e.g. gdc-ui's own `modules/tsconfig.*.json`). Default: false — clients
|
|
165
|
+
* scaffolding into arbitrary repos need the self-contained bundled version.
|
|
166
|
+
*/
|
|
167
|
+
readonly preferWorkspaceTemplate?: boolean;
|
|
168
|
+
/** Derives route, ports, menu order, federation name, etc. Runs after prompts, before copy. */
|
|
169
|
+
derive(answers: IScaffoldAnswers, repo: IRepoInfo): IDerivedValues;
|
|
170
|
+
/** Ordered token → replacement pairs applied to every text file under each subtree on copy. */
|
|
171
|
+
buildReplacements(ctx: IProfileContext): TokenReplacements;
|
|
172
|
+
/**
|
|
173
|
+
* In-place transform of each copied module/harness package.json. Used by the
|
|
174
|
+
* client profile to rewrite `workspace:*` deps to concrete semver — internal
|
|
175
|
+
* leaves them as `workspace:*`.
|
|
176
|
+
*/
|
|
177
|
+
transformPackageJson(pkg: Record<string, unknown>, ctx: IProfileContext): Record<string, unknown>;
|
|
178
|
+
/**
|
|
179
|
+
* Files in the host repo that must be edited to register the new app
|
|
180
|
+
* (rush.json, host registry, dockerfiles, etc.). Single source of truth —
|
|
181
|
+
* the engine uses this list for both the pre-flight anchor check AND the
|
|
182
|
+
* actual insertion pass, so the two can't drift.
|
|
183
|
+
*
|
|
184
|
+
* Returns empty for fully-decoupled scaffolds.
|
|
185
|
+
*
|
|
186
|
+
* Profile authors use `repo` to gate steps on filesystem state (e.g. client
|
|
187
|
+
* skips the rush.json registration unless `repo.packageManager === "rush"`).
|
|
188
|
+
* The same list is consumed by pre-flight `checkAnchors` (before prompts/derive)
|
|
189
|
+
* and by the post-copy insertion pass, so don't make this depend on answers.
|
|
190
|
+
*/
|
|
191
|
+
registrations(repo: IRepoInfo): readonly IRegistrationStep[];
|
|
192
|
+
/** Final step after copy + register: rush update / npm install / no-op. */
|
|
193
|
+
postCopy(ctx: IProfileContext): Promise<void>;
|
|
194
|
+
}
|
package/esm/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gooddata/create-pluggable-module",
|
|
3
|
+
"version": "11.40.0-alpha.3",
|
|
4
|
+
"description": "Scaffolder for GoodData pluggable applications. Invoked via `npm init @gooddata/pluggable-module`.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "GoodData Corporation",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/gooddata/gooddata-ui-sdk.git",
|
|
10
|
+
"directory": "tools/create-pluggable-module"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"create-pluggable-module": "./esm/index.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"esm/**/*.js",
|
|
17
|
+
"esm/**/*.json",
|
|
18
|
+
"esm/**/*.d.ts",
|
|
19
|
+
"esm/**/*.map",
|
|
20
|
+
"dist/templates/**"
|
|
21
|
+
],
|
|
22
|
+
"type": "module",
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"main": "./esm/index.js",
|
|
25
|
+
"types": "./esm/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./esm/index.d.ts",
|
|
29
|
+
"default": "./esm/index.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "24.12.0",
|
|
34
|
+
"@typescript-eslint/eslint-plugin": "8.58.0",
|
|
35
|
+
"@typescript-eslint/parser": "8.58.0",
|
|
36
|
+
"@typescript/native-preview": "7.0.0-dev.20260202.1",
|
|
37
|
+
"eslint": "^9.39.2",
|
|
38
|
+
"eslint-import-resolver-typescript": "4.4.4",
|
|
39
|
+
"eslint-plugin-headers": "1.3.3",
|
|
40
|
+
"eslint-plugin-import-esm": "1.2.1",
|
|
41
|
+
"eslint-plugin-import-x": "4.16.1",
|
|
42
|
+
"eslint-plugin-jsdoc": "62.1.0",
|
|
43
|
+
"eslint-plugin-no-barrel-files": "1.2.2",
|
|
44
|
+
"eslint-plugin-sonarjs": "3.0.6",
|
|
45
|
+
"npm-run-all": "^4.1.5",
|
|
46
|
+
"oxfmt": "0.45.0",
|
|
47
|
+
"oxlint": "^1.43.0",
|
|
48
|
+
"oxlint-tsgolint": "0.11.4",
|
|
49
|
+
"tslib": "2.8.1",
|
|
50
|
+
"typescript": "5.9.3",
|
|
51
|
+
"vite": "8.0.0",
|
|
52
|
+
"vitest": "4.1.0",
|
|
53
|
+
"@gooddata/oxlint-config": "11.40.0-alpha.3",
|
|
54
|
+
"@gooddata/eslint-config": "11.40.0-alpha.3",
|
|
55
|
+
"gdc-app-template-name-harness": "11.40.0-alpha.3",
|
|
56
|
+
"gdc-app-template-name-module": "11.40.0-alpha.3"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=24.12.0"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"_phase:build": "npm run build",
|
|
63
|
+
"_phase:test": "npm run test-once",
|
|
64
|
+
"_phase:validate": "npm run validate",
|
|
65
|
+
"build": "npm-run-all -p build-check build-ts",
|
|
66
|
+
"build-check": "tsgo",
|
|
67
|
+
"build-ts": "tsgo -p tsconfig.build.json",
|
|
68
|
+
"clean": "../../common/scripts/clean-command-state.sh && rm -rf ci dist esm coverage *.log tsconfig.tsbuildinfo",
|
|
69
|
+
"format-check": "oxfmt --check .",
|
|
70
|
+
"format-write": "oxfmt .",
|
|
71
|
+
"lint": "oxlint . --type-aware --quiet && eslint src",
|
|
72
|
+
"lint-fix": "oxlint . --type-aware --quiet --fix && eslint src --fix",
|
|
73
|
+
"test": "vitest watch",
|
|
74
|
+
"test-once": "vitest run --passWithNoTests",
|
|
75
|
+
"validate": "npm run lint && npm run format-check"
|
|
76
|
+
}
|
|
77
|
+
}
|