Skip to content

Commit

Permalink
Indent variable declaration
Browse files Browse the repository at this point in the history
working on #3
  • Loading branch information
gparlakov committed Mar 19, 2020
1 parent ca0c9fb commit 888a022
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 120 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
**/*.js
**/*.js.map
**/*.d.ts
!jest.config.js

# IDEs
.idea/
Expand All @@ -20,3 +19,7 @@ yarn-error.log*
dist

*.tgz

# Project specific
!jest.config.js
**/*.skip-me.ts
84 changes: 58 additions & 26 deletions src/spec/update/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function addMissing(
path: string,
fileContent: string,
_dependencies: ConstructorParam[],
_classUnderTestName: string
classUnderTestName: string
) {
const source = ts.createSourceFile(path, fileContent, ts.ScriptTarget.Latest, true);

Expand All @@ -28,7 +28,7 @@ function setup() {
return builder;
},
build() {
return new ${_classUnderTestName}();
return new ${classUnderTestName}();
}
}
return builder;
Expand Down Expand Up @@ -151,11 +151,9 @@ function add(
throw new Error('Could not find the block of the setup function.');
}

const blockIndentation = ' ';

return [
...declareNewDependencies(block, toAdd, path, blockIndentation),
...exposeNewDependencies(block, toAdd, path, blockIndentation),
...declareNewDependencies(block, toAdd, path),
...exposeNewDependencies(block, toAdd, path),
...useNewDependenciesInConstructor(block, toAdd, path, classUnderTestName)
];
}
Expand All @@ -164,11 +162,15 @@ function declareNewDependencies(
block: ts.Block,
toAdd: ConstructorParam[],
path: string,
indentation?: string
_indentation?: string
) {
// children of the block are the opening { the block content (SyntaxList) and the closing }
// children of the block are the opening { [at index [0]], the block content (SyntaxList) [at index[1]] and the closing } [index [2]]
// we want to update the SyntaxList
const setupBlockContent = block.getChildAt(1);

// leading because it includes the end-of-line from previous line plus indentation on current line
const leadingIndent = getIndentationMinusComments(setupBlockContent);

const position = setupBlockContent.getStart();
return toAdd.map(
p =>
Expand All @@ -182,18 +184,13 @@ function declareNewDependencies(
p.type === 'any' ||
p.type === 'unknown' ||
p.type === 'Object'
? `let ${p.name}: ${p.type};${EOL}${indentation}`
: `const ${p.name} = autoSpy(${p.type});${EOL}${indentation}`
? `let ${p.name}: ${p.type};` + leadingIndent
: `const ${p.name} = autoSpy(${p.type});` + leadingIndent
)
);
}

function exposeNewDependencies(
block: ts.Block,
toAdd: ConstructorParam[],
path: string,
indentation?: string
) {
function exposeNewDependencies(block: ts.Block, toAdd: ConstructorParam[], path: string) {
const builderDeclaration = findNodes(block, ts.SyntaxKind.VariableDeclaration).find(v =>
(v as ts.VariableDeclaration).name.getFullText().includes('builder')
);
Expand All @@ -204,8 +201,11 @@ function exposeNewDependencies(
if (builderDeclaration == null || builderObjectLiteral == null) {
throw new Error('Could not find the builder declaration or its object literal.');
}

const indentation = getIndentationMinusComments(builderObjectLiteral.getChildAt(1));

const positionToAdd = builderObjectLiteral.getChildAt(0).getEnd();
return toAdd.map(a => new InsertChange(path, positionToAdd, `${EOL}${indentation}${a.name},`));
return toAdd.map(a => new InsertChange(path, positionToAdd, `${indentation}${a.name},`));
}

function useNewDependenciesInConstructor(
Expand Down Expand Up @@ -381,34 +381,56 @@ function findTheParentBlock(node: ts.Node): ts.Node {
}
}

function getIndentationMinusComments(node: ts.Node) {
if (node == null) {
return '';
}
const leadingTrivia = node.getFullText().replace(node.getText(), '');
let index = leadingTrivia.indexOf(EOL);
return index < 0 ? leadingTrivia : leadingTrivia.slice(index);
}

//@ts-ignore
function _printKindAndText(node?: ts.Node[] | ts.Node | null) {
function _printKindAndText(node?: ts.Node[] | ts.Node | null, printOutSpaces = false) {
if (node != null) {
if (Array.isArray(node)) {
node.forEach(_printKindAndText);
node.forEach(n => _printKindAndText(n, printOutSpaces));
} else {
// tslint:disable-next-line:no-console
console.log(ts.SyntaxKind[node.kind], node.getText(), EOL);
console.log(
_formatTextWithSpaces(node, printOutSpaces),
'kind:',
ts.SyntaxKind[node.kind],
EOL
);
}
} else {
// tslint:disable-next-line:no-console
console.log('this is empty');
}
}

let depth = 1;
let maxDepth = 5;
//@ts-ignore
function _printKindAndTextRecursive(node?: ts.Node[] | ts.Node | null) {
function _printKindAndTextRecursive(node?: ts.Node[] | ts.Node | null, printOutSpaces = false) {
if (node != null) {
if (Array.isArray(node)) {
node.forEach(_printKindAndTextRecursive);
node.forEach(c => _printKindAndTextRecursive(c, printOutSpaces));
} else {
// tslint:disable-next-line:no-console
console.log(ts.SyntaxKind[node.kind], node.getText(), depth, EOL);
console.log(
_formatTextWithSpaces(node, printOutSpaces),
EOL,
'kind:',
ts.SyntaxKind[node.kind],
'depth:',
depth,
EOL
);
depth += 1;
const children = node.getChildren();
if (Array.isArray(children) && depth < 6) {
_printKindAndTextRecursive(children);
if (Array.isArray(children) && depth <= maxDepth) {
_printKindAndTextRecursive(children, printOutSpaces);
}
depth -= 1;
}
Expand All @@ -417,3 +439,13 @@ function _printKindAndTextRecursive(node?: ts.Node[] | ts.Node | null) {
console.log('this is empty');
}
}

function _formatTextWithSpaces(node: ts.Node | string, printOutSpaces: boolean) {
const text = typeof node === 'string' ? node : node.getFullText();
return printOutSpaces
? text
.replace(/(\r\n|\r|\n)/g, 'NEW_LINE_MF')
.replace(/\s/g, '•')
.replace(/NEW_LINE_MF/g, '¶' + EOL)
: text;
}
18 changes: 0 additions & 18 deletions tests/spec/formatter.ts

This file was deleted.

159 changes: 84 additions & 75 deletions tests/spec/spec-update.indentation-format.spec.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,84 @@
import { Tree } from '@angular-devkit/schematics';
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
import { filter } from 'rxjs/operators';
import { collectionPath } from './common';

describe('Calling update on existing specs without setup function', () => {
let tree = Tree.empty();

beforeEach(() => {
tree = Tree.empty();
tree.create(
'c.ts',
`import { LogService, BDep } from '@angular/core';
export class C {
constructor(
private bDep: bDep,
private logger: LogService
) {}
}`
);

tree.create(
'c.spec.ts',
`import { bDep } from '@angular/core';
describe('C', () => {
});`
);
});

xit('should pass successfully', () => {
// arrange
const runner = new SchematicTestRunner('schematics', collectionPath);
// act
const errors = [];
runner.logger.pipe(filter(v => v.level === 'error')).subscribe(v => errors.push(v));
runner.runSchematic('spec', { name: './c.ts', update: true }, tree);
// assert
expect(errors.length).toBe(0);
});

it('should create the setup function and then update it', () => {
// arrange
const runner = new SchematicTestRunner('schematics', collectionPath);
// act
const result = runner.runSchematic('spec', { name: './c.ts', update: true }, tree);
// assert
// @ts-ignore
const contents = result.readContent('./c.spec.ts');
// update should add LogService to imports, to construct params and create a spy for it
expect(contents).toMatchInlineSnapshot(`
"import { LogService } from '@angular/core';
import { bDep } from '@angular/core';
describe('C', () => {
});
function setup() {
const bDep = autoSpy(bDep);
const logger = autoSpy(LogService);
const builder = {
bDep,
logger,
default() {
return builder;
},
build() {
return new C(bDep, logger);
}
}
return builder;
}"
`);
});
});
import { Tree } from '@angular-devkit/schematics';
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
import { filter } from 'rxjs/operators';
import { collectionPath } from './common';

describe('Calling update on existing specs without setup function', () => {
let tree = Tree.empty();

beforeEach(() => {
tree = Tree.empty();
tree.create(
'c.ts',
`import { LogService, BDep } from '@angular/core';
export class C {
constructor(
private aDep: BDep,
private bDep: BDep,
private cDep: BDep,
private logger: LogService
) {}
}`
);

tree.create(
'c.spec.ts',
`import { bDep } from '@angular/core';
describe('C', () => {
});`
);
});

it('should pass successfully', () => {
// arrange
const runner = new SchematicTestRunner('schematics', collectionPath);
// act
const errors = [];
runner.logger.pipe(filter(v => v.level === 'error')).subscribe(v => errors.push(v));
runner.runSchematic('spec', { name: './c.ts', update: true }, tree);
// assert
expect(errors.length).toBe(0);
});

it('should indent setup function variable declarations', () => {
// arrange
const runner = new SchematicTestRunner('schematics', collectionPath);
// act
const result = runner.runSchematic('spec', { name: './c.ts', update: true }, tree);
// assert
// @ts-ignore
const contents = result.readContent('./c.spec.ts');
// update should add LogService to imports, to construct params and create a spy for it
expect(contents).toMatchInlineSnapshot(`
"import { BDep } from '@angular/core';
import { BDep } from '@angular/core';
import { BDep } from '@angular/core';
import { LogService } from '@angular/core';
import { bDep } from '@angular/core';
describe('C', () => {
});
function setup() {
const aDep = autoSpy(BDep);
const bDep = autoSpy(BDep);
const cDep = autoSpy(BDep);
const logger = autoSpy(LogService);
const builder = {
aDep,
bDep,
cDep,
logger,
default() {
return builder;
},
build() {
return new C(aDep, bDep, cDep, logger);
}
}
return builder;
}"
`);
});
});

0 comments on commit 888a022

Please sign in to comment.