Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

export types from command #27133

Merged
merged 2 commits into from
Aug 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions generators/base-core/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -598,12 +598,12 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`);
return Object.entries(configs)
.filter(([_name, def]) => def?.prompt)
.map(([name, def]) => {
const promptSpec = typeof def.prompt === 'function' ? def.prompt(this as any, def) : { ...def.prompt };
let promptSpec = typeof def.prompt === 'function' ? def.prompt(this as any, def) : { ...def.prompt };
let storage: any;
if ((def.scope ?? 'storage') === 'storage') {
storage = this.config;
if (promptSpec.default === undefined) {
promptSpec.default = () => (this as any).jhipsterConfigWithDefaults?.[name];
promptSpec = { ...promptSpec, default: () => (this as any).jhipsterConfigWithDefaults?.[name] };
}
} else if (def.scope === 'blueprint') {
storage = this.blueprintStorage;
Expand Down Expand Up @@ -631,7 +631,7 @@ You can ignore this error by passing '--skip-checks' to jhipster command.`);
*/
dateFormatForLiquibase(reproducible?: boolean) {
const control = this.sharedData.getControl();
reproducible = reproducible ?? control.reproducible;
reproducible = reproducible ?? Boolean(control.reproducible);
// Use started counter or use stored creationTimestamp if creationTimestamp option is passed
const creationTimestamp = this.options.creationTimestamp ? this.config.get('creationTimestamp') : undefined;
let now = new Date();
Expand Down
111 changes: 82 additions & 29 deletions generators/base/api.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { ArgumentSpec, BaseFeatures, BaseOptions, CliOptionSpec } from 'yeoman-generator';
import type { RequireAtLeastOne, SetOptional } from 'type-fest';
import type { RequireAtLeastOne, SetOptional, TaggedUnion } from 'type-fest';
import type CoreGenerator from '../base-core/index.js';

type ConfigScope = 'storage' | 'blueprint' | 'control' | 'generator';
type CliSpecType = CliOptionSpec['type'];

export type ApplicationWithConfig = {
config: Record<string, string | boolean | number | string[]>;
entities: Record<string, unknown>;
Expand Down Expand Up @@ -192,13 +195,13 @@ export type WriteFileOptions<Generator = CoreGenerator, DataType = any> = {
}
);

export type JHispterChoices = string[] | { value: string; name: string }[];
export type JHispterChoices = readonly string[] | readonly { value: string; name: string }[];

export type JHipsterOption = SetOptional<CliOptionSpec, 'name'> & {
name?: string;
scope?: 'storage' | 'blueprint' | 'control' | 'generator';
env?: string;
choices?: JHispterChoices;
readonly name?: string;
readonly scope?: 'storage' | 'blueprint' | 'control' | 'generator';
readonly env?: string;
readonly choices?: JHispterChoices;
};

export type ValidationResult = {
Expand All @@ -209,25 +212,27 @@ export type ValidationResult = {
};

export type PromptSpec = {
type: 'input' | 'list' | 'confirm' | 'checkbox';
message: string | ((any) => string);
when?: boolean | ((any) => boolean);
default?: any | ((any) => any);
filter?: any | ((any) => any);
transformer?: any | ((any) => any);
validate?: any | ((any) => any);
readonly type: 'input' | 'list' | 'confirm' | 'checkbox';
readonly message: string | ((any) => string);
readonly when?: boolean | ((any) => boolean);
readonly default?: any | ((any) => any);
readonly filter?: any | ((any) => any);
readonly transformer?: any | ((any) => any);
readonly validate?: any | ((any) => any);
};

export type JHipsterArgumentConfig = SetOptional<ArgumentSpec, 'name'> & { scope?: 'storage' | 'blueprint' | 'generator' };

export type ConfigSpec = {
description?: string;
choices?: JHispterChoices;

cli?: SetOptional<CliOptionSpec, 'name'> & { env?: string };
argument?: JHipsterArgumentConfig;
prompt?: PromptSpec | ((gen: CoreGenerator & { jhipsterConfigWithDefaults: Record<string, any> }, config: ConfigSpec) => PromptSpec);
scope?: 'storage' | 'blueprint' | 'generator';
readonly description?: string;
readonly choices?: JHispterChoices;

readonly cli?: SetOptional<CliOptionSpec, 'name'> & { env?: string };
readonly argument?: JHipsterArgumentConfig;
readonly prompt?:
| PromptSpec
| ((gen: CoreGenerator & { jhipsterConfigWithDefaults: Record<string, any> }, config: ConfigSpec) => PromptSpec);
readonly scope?: 'storage' | 'blueprint' | 'generator';
/**
* The callback receives the generator as input for 'generator' scope.
* The callback receives jhipsterConfigWithDefaults as input for 'storage' (default) scope.
Expand All @@ -236,11 +241,16 @@ export type ConfigSpec = {
* Default value will not be applied to generator (using 'generator' scope) in initializing priority. Use cli.default instead.
* Default value will be application to templates context object (application) in loading priority.
*/
default?: string | boolean | number | string[] | ((this: CoreGenerator | void, ctx: any) => string | boolean | number | string[]);
readonly default?:
| string
| boolean
| number
| readonly string[]
| ((this: CoreGenerator | void, ctx: any) => string | boolean | number | readonly string[]);
/**
* Configure the generator according to the selected configuration.
*/
configure?: (gen: CoreGenerator) => void;
readonly configure?: (gen: CoreGenerator) => void;
};

export type JHipsterArguments = Record<string, JHipsterArgumentConfig>;
Expand All @@ -250,26 +260,69 @@ export type JHipsterOptions = Record<string, JHipsterOption>;
export type JHipsterConfigs = Record<string, RequireAtLeastOne<ConfigSpec, 'argument' | 'cli' | 'prompt'>>;

export type JHipsterCommandDefinition = {
arguments?: JHipsterArguments;
options?: JHipsterOptions;
configs?: JHipsterConfigs;
readonly arguments?: JHipsterArguments;
readonly options?: JHipsterOptions;
readonly configs?: JHipsterConfigs;
/**
* Import options from a generator.
* @example ['server', 'jhipster-blueprint:server']
*/
import?: string[];
readonly import?: readonly string[];
/**
* @experimental
* Compose with generator.
* @example ['server', 'jhipster-blueprint:server']
*/
compose?: string[];
readonly compose?: readonly string[];
/**
* Override options from the generator been blueprinted.
*/
override?: boolean;
readonly override?: boolean;
/**
* Load old options definition (yeoman's `this.options()`) from the generator.
*/
loadGeneratorOptions?: boolean;
readonly loadGeneratorOptions?: boolean;
};

/**
* A simplified version of the `JHipsterCommandDefinition` type for types parsing.
*/
type ParseableConfig = {
type?: CliSpecType;
cli?: {
type: CliSpecType;
};
scope: ConfigScope;
};
type ParseableCommand = {
readonly options?: Record<any, ParseableConfig>;
readonly configs?: Record<any, ParseableConfig>;
};

/** Extract contructor return type, eg: Boolean, String */
type ConstructorReturn<T> = T extends new () => infer R ? R : any;
type FilteredConfigScope = ConfigScope | undefined;
/** Add name to Options/Configs */
type TaggedParseableConfigUnion<D> = D extends Record<string, any> ? TaggedUnion<'name', D> : never;
/** Get union of Options and Configs */
type CommandUnion<C extends ParseableCommand> = TaggedParseableConfigUnion<C['configs']> | TaggedParseableConfigUnion<C['options']>;
type GetType<C extends ParseableConfig> =
C extends Record<'type', CliSpecType> ? C['type'] : C extends Record<'cli', Record<'type', CliSpecType>> ? C['cli']['type'] : never;
// eslint-disable-next-line @typescript-eslint/no-wrapper-object-types
type WrapperToPrimitive<T> = T extends boolean ? Boolean : T extends String ? string : T extends Number ? number : T;

type UnionToObject<U extends { name: string; scope: ConfigScope }> = {
[K in U as K['name']]?: WrapperToPrimitive<ConstructorReturn<GetType<K>>>;
};

/** Filter Options/Config by scope */
type FilterScope<D, S extends FilteredConfigScope> =
D extends Record<'scope', S> ? D : D extends Record<'scope', ConfigScope> ? never : S extends undefined ? D : never;

export type ExportStoragePropertiesFromCommand<C extends ParseableCommand> = UnionToObject<FilterScope<CommandUnion<C>, 'storage'>>;

export type ExportGeneratorPropertiesFromCommand<C extends ParseableCommand> = UnionToObject<FilterScope<CommandUnion<C>, 'generator'>>;

export type ExportControlPropertiesFromCommand<C extends ParseableCommand> = UnionToObject<FilterScope<CommandUnion<C>, 'control'>>;

export type ExportBlueprintPropertiesFromCommand<C extends ParseableCommand> = UnionToObject<FilterScope<CommandUnion<C>, 'blueprint'>>;
12 changes: 8 additions & 4 deletions generators/base/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { JHipsterCommandDefinition } from '../base/api.js';
import { asCommand } from '../type-utils.js';

const command: JHipsterCommandDefinition = {
const command = {
options: {
useVersionPlaceholders: {
description: 'replace mutable versions with placeholders',
Expand All @@ -41,6 +41,7 @@ const command: JHipsterCommandDefinition = {
disableBlueprints: {
description: 'Disable blueprints support',
type: Boolean,
scope: 'generator',
},
debugEnabled: {
name: 'debug',
Expand All @@ -57,6 +58,7 @@ const command: JHipsterCommandDefinition = {
skipPrompts: {
description: 'Skip prompts',
type: Boolean,
scope: 'generator',
},
ignoreNeedlesError: {
description: 'Ignore needles failures',
Expand All @@ -65,6 +67,8 @@ const command: JHipsterCommandDefinition = {
scope: 'generator',
},
},
};
} as const;

export type Command = typeof command;

export default command;
export default asCommand(command);
7 changes: 5 additions & 2 deletions generators/base/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import type { Entity } from '../base-application/index.ts';
import { ExportControlPropertiesFromCommand } from './api.js';
import type { Command } from './command.ts';

export type Control = {
type BaseApplicationControlProperties = ExportControlPropertiesFromCommand<Command>;

export type Control = BaseApplicationControlProperties & {
existingProject: boolean;
ignoreNeedlesError: boolean;
jhipsterOldVersion: string | null;
useVersionPlaceholders?: boolean;
reproducible?: boolean;
/**
* Configure blueprints once per application.
*/
Expand Down
14 changes: 11 additions & 3 deletions generators/client/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const promptValueToMicrofrontends = answer =>
.map(baseName => ({ baseName }))
: [];

const command: JHipsterCommandDefinition = {
const command = {
options: {},
configs: {
clientFramework: {
Expand All @@ -57,6 +57,7 @@ const command: JHipsterCommandDefinition = {
{ value: VUE, name: 'Vue' },
{ value: CLIENT_FRAMEWORK_NO, name: 'No client' },
],
scope: 'storage',
},
microfrontend: {
description: 'Enable microfrontend support',
Expand All @@ -71,6 +72,7 @@ const command: JHipsterCommandDefinition = {
message: `Do you want to enable ${chalk.yellow('*microfrontends*')}?`,
default: false,
}),
scope: 'storage',
},
microfrontends: {
description: 'Microfrontends to load',
Expand All @@ -95,6 +97,7 @@ const command: JHipsterCommandDefinition = {
filter: promptValueToMicrofrontends,
transformer: microfrontendsToPromptValue,
}),
scope: 'storage',
},
clientTestFrameworks: {
description: 'Client test frameworks',
Expand All @@ -105,6 +108,7 @@ const command: JHipsterCommandDefinition = {
default: () => intersection([CYPRESS], config.testFrameworks),
}),
choices: [{ name: 'Cypress', value: CYPRESS }],
scope: 'storage',
},
withAdminUi: {
description: 'Generate administrative user interface',
Expand All @@ -116,15 +120,19 @@ const command: JHipsterCommandDefinition = {
when: answers => [ANGULAR, REACT, VUE].includes(answers.clientFramework ?? config.clientFramework),
message: 'Do you want to generate the admin UI?',
}),
scope: 'storage',
},
clientRootDir: {
description: 'Client root',
cli: {
type: String,
},
scope: 'storage',
},
},
import: [GENERATOR_COMMON],
};
} as const;

export default command;
export type Command = typeof command;

export default command as JHipsterCommandDefinition;
8 changes: 6 additions & 2 deletions generators/client/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import type { addIconImport, addItemToMenu, addRoute } from '../angular/support/needles.js';
import type { AngularApplication } from '../angular/types.js';
import type { OptionWithDerivedProperties } from '../base-application/application-options.js';
import type { ExportStoragePropertiesFromCommand } from '../base/api.js';
import type { CypressApplication } from '../cypress/types.js';
import type { JavaScriptApplication, JavaScriptSourceType } from '../javascript/types.js';
import type { Command } from './command.ts';

type ClientFrameworkType = ['no', 'angular', 'react', 'vue', 'svelte'];

type ClientFrameworkApplication = OptionWithDerivedProperties<'clientFramework', ClientFrameworkType>;

export type ClientApplication = ClientFrameworkApplication &
type ApplicationClientProperties = ExportStoragePropertiesFromCommand<Command>;

export type ClientApplication = ApplicationClientProperties &
ClientFrameworkApplication &
JavaScriptApplication &
AngularApplication &
CypressApplication & {
withAdminUi: boolean;
webappLoginRegExp: string;
webappEnumerationsDir?: string;
};
Expand Down
2 changes: 2 additions & 0 deletions generators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export {
CLIENT_TEST_SRC_DIR as TEMPLATES_JAVASCRIPT_TEST_DIR,
} from './generator-constants.js';

export * from './type-utils.js';

export type { JHipsterCommandDefinition } from './base/api.js';

export { default as GeneratorBase } from './base/index.js';
Expand Down
8 changes: 5 additions & 3 deletions generators/java/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { JHipsterCommandDefinition } from '../base/api.js';
import { asCommand } from '../type-utils.js';

const command: JHipsterCommandDefinition = {
const command = {
options: {},
import: ['jhipster:java:bootstrap', 'jhipster:java:domain', 'jhipster:java:build-tool'],
};

export default command;
export type Coomand = typeof command;

export default asCommand(command);
13 changes: 8 additions & 5 deletions generators/java/generators/bootstrap/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { JHipsterCommandDefinition } from '../../../base/api.js';
import { PromptSpec } from '../../../base/api.js';
import { asCommand } from '../../../type-utils.js';

const command: JHipsterCommandDefinition = {
const command = {
options: {
withGeneratedFlag: {
description: 'Add a GeneratedByJHipster annotation to all generated java classes and interfaces',
Expand All @@ -38,7 +39,7 @@ const command: JHipsterCommandDefinition = {
cli: {
type: String,
},
prompt: gen => ({
prompt: (gen): PromptSpec => ({
type: 'input',
message: 'What is your default Java package name?',
default: gen.jhipsterConfigWithDefaults.packageName,
Expand All @@ -52,6 +53,8 @@ const command: JHipsterCommandDefinition = {
},
},
import: [],
};
} as const;

export default command;
export type Command = typeof command;

export default asCommand(command);
Loading
Loading