Skip to content

Commit

Permalink
feat(cli): allow build repo class without constructor (#493)
Browse files Browse the repository at this point in the history
  • Loading branch information
EricPoul authored Oct 14, 2023
1 parent 2ca0170 commit 8f5f351
Show file tree
Hide file tree
Showing 10 changed files with 446 additions and 54 deletions.
2 changes: 1 addition & 1 deletion docs/docs/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ You can set the configuration by providing the `package.json` file:
By default, the `repository` file generates exported functions. If you prefer to use a class, for instance, when working with Angular, you can set this option to `class`.

### `inlineStoreInClass`
By default, a store is created outside of the class. If you prefer creating the store inside a class you can set this option to `true`. It might be helpful when you create a `component store` or you want to set the initial value to the store given via Angular DI (Works only with `repoTemplate` set as `class`).
By default, a store is created outside of the class. If you prefer creating the store inside a class you can set this option to `true` or `withoutConstructor`. It might be helpful when you create a `component store` or you want to set the initial value to the store given via Angular DI (Works only with `repoTemplate` set as `class`).

### `idKey`
The default `idKey` for the package `@ngneat/elf-entities` is `id`. By setting this option, you can change it globally.
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/builders/active-id.builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ export class ActiveIdBuilder extends FeatureBuilder {
kind: StructureKind.Property,
};

if (this.isStoreInlinedInClass) {
if (this.repoConstructor) {
this.repo.insertProperty(0, {
...memberData,
type: `Observable<${this.storeSingularNames.className} | undefined>`,
});

this.repoConstructor?.addStatements(
this.repoConstructor.addStatements(
`this.${memberData.name} = ${initializer};`
);
} else {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/builders/active-ids.builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ export class ActiveIdsBuilder extends FeatureBuilder {
kind: StructureKind.Property,
};

if (this.isStoreInlinedInClass) {
if (this.repoConstructor) {
this.repo.insertProperty(0, {
...memberData,
type: `Observable<${this.storeSingularNames.className}[]>`,
});

this.repoConstructor?.addStatements(
this.repoConstructor.addStatements(
`this.${memberData.name} = ${initializer};`
);
} else {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/builders/entities.builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,15 @@ export class EntitiesBuilder extends FeatureBuilder {
kind: StructureKind.Property,
};

if (this.isStoreInlinedInClass) {
if (this.repoConstructor) {
this.addImport('Observable', 'rxjs');

this.repo.insertProperty(0, {
...memberData,
type: `Observable<${this.storeSingularNames.className}[]>`,
});

this.repoConstructor?.addStatements(
this.repoConstructor.addStatements(
`this.${memberData.name} = ${initializer};`
);
} else {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/builders/feature-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export abstract class FeatureBuilder {
protected repo: ClassDeclaration,
protected options: Options
) {
if (this.isStoreInlinedInClass) {
if (this.isStoreInlinedInClass === true) {
this.repoConstructor = this.repo.getConstructors()[0];
}
}
Expand Down
108 changes: 68 additions & 40 deletions packages/cli/src/builders/repo-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export function createRepo(options: Options) {
const storeNames = names(storeName);
const isFunctionTpl = !options.template || options.template === 'functions';
const isStoreInlinedInClass = !isFunctionTpl && options.inlineStoreInClass;
const classWithConstructor = isStoreInlinedInClass !== 'withoutConstructor';

const project = new Project({
manipulationSettings: {
Expand All @@ -46,7 +47,7 @@ export function createRepo(options: Options) {
});
let repoClassDecConstructor: ConstructorDeclaration | undefined;

if (isStoreInlinedInClass) {
if (isStoreInlinedInClass && classWithConstructor) {
repoClassDec.addConstructor();
repoClassDecConstructor = repoClassDec.getConstructors()[0];
}
Expand Down Expand Up @@ -91,14 +92,21 @@ export function createRepo(options: Options) {
[storeOpts, ...propsFactories]
);

if (isStoreInlinedInClass && repoClassDecConstructor) {
addInlineStoreToRepoClass({
repoClassDec,
repoClassDecConstructor,
options,
store,
storeNames,
});
if (isStoreInlinedInClass) {
if (repoClassDecConstructor) {
addInlineStoreToRepoClass({
repoClassDec,
repoClassDecConstructor,
options,
store,
storeNames,
});
} else {
addInlineStoreToRepoClassWithoutConstructor({
repoClassDec,
store,
});
}
} else {
addStoreToRepo({
repoClassDec,
Expand Down Expand Up @@ -170,22 +178,16 @@ function addInlineStoreToRepoClass({
storeNames,
true
);
const { propertyIndex, methodIndex } = getPositionsOfInlineStoreDeclarations(
classDec,
constructorDec
);

const createStoreMethodName = 'createStore';
const lastPropertyIndex = classDec
.getLastChildByKind(SyntaxKind.PropertyDeclaration)
?.getChildIndex();
const propertyIndex = lastPropertyIndex
? lastPropertyIndex + 1
: constructorDec.getChildIndex();

classDec.insertMethod(methodIndex, {
name: createStoreMethodName,
returnType: `typeof store`,
scope: Scope.Private,
statements: (writer) => {
writer.writeLine(`const store = ${printNode(store)};`);
writer.blankLine();
writer.writeLine(`return store;`);
},
const createStoreMethodName = addCreateStoreMethod({
repoClassDec: classDec,
store,
});

constructorDec.insertStatements(
Expand All @@ -203,6 +205,28 @@ function addInlineStoreToRepoClass({
}
}

function addInlineStoreToRepoClassWithoutConstructor({
repoClassDec: classDec,
store,
}: {
repoClassDec: ClassDeclaration;
store: CallExpression;
}) {
const createStoreMethodName = addCreateStoreMethod({
repoClassDec: classDec,
store,
});

classDec.insertProperty(0, {
name: 'store',
scope: Scope.Private,
isReadonly: true,
initializer: `this.${createStoreMethodName}()`,
});

classDec.insertMember(1, '\n');
}

function toFunctions(sourceFile: SourceFile, classDec: ClassDeclaration) {
const exported: string[] = [];

Expand All @@ -221,21 +245,25 @@ function toFunctions(sourceFile: SourceFile, classDec: ClassDeclaration) {
);
}

function getPositionsOfInlineStoreDeclarations(
classDec: ClassDeclaration,
constructorDec: ConstructorDeclaration
) {
const lastPropertyIndex = classDec
.getLastChildByKind(SyntaxKind.PropertyDeclaration)
?.getChildIndex();
const lastMethodIndex = classDec
.getLastChildByKind(SyntaxKind.MethodDeclaration)
?.getChildIndex();
function addCreateStoreMethod({
repoClassDec: classDec,
store,
}: {
repoClassDec: ClassDeclaration;
store: CallExpression;
}): string {
const createStoreMethodName = 'createStore';

classDec.addMethod({
name: createStoreMethodName,
returnType: `typeof store`,
scope: Scope.Private,
statements: (writer) => {
writer.writeLine(`const store = ${printNode(store)};`);
writer.blankLine();
writer.writeLine(`return store;`);
},
});

return {
methodIndex: (lastMethodIndex ?? constructorDec.getChildIndex()) + 1,
propertyIndex: lastPropertyIndex
? lastPropertyIndex + 1
: constructorDec.getChildIndex(),
};
return createStoreMethodName;
}
Loading

0 comments on commit 8f5f351

Please sign in to comment.