Skip to content

Commit

Permalink
test(parser): change parser tests to check scope analysis (#234)
Browse files Browse the repository at this point in the history
  • Loading branch information
armano2 committed Feb 12, 2019
1 parent 43b3c00 commit 929189b
Show file tree
Hide file tree
Showing 15 changed files with 92,234 additions and 280,886 deletions.
4,101 changes: 1,122 additions & 2,979 deletions packages/parser/tests/lib/__snapshots__/basics.ts.snap

Large diffs are not rendered by default.

187,065 changes: 53,892 additions & 133,173 deletions packages/parser/tests/lib/__snapshots__/javascript.ts.snap

Large diffs are not rendered by default.

14,465 changes: 1,439 additions & 13,026 deletions packages/parser/tests/lib/__snapshots__/jsx.ts.snap

Large diffs are not rendered by default.

1,939 changes: 235 additions & 1,704 deletions packages/parser/tests/lib/__snapshots__/tsx.ts.snap

Large diffs are not rendered by default.

165,068 changes: 35,283 additions & 129,785 deletions packages/parser/tests/lib/__snapshots__/typescript.ts.snap

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions packages/parser/tests/lib/basics.ts
Expand Up @@ -2,7 +2,10 @@ import { Linter } from 'eslint';
import fs from 'fs';
import glob from 'glob';
import * as parser from '../../src/parser';
import * as testUtils from '../../tools/test-utils';
import {
createScopeSnapshotTestBlock,
formatSnapshotName
} from '../tools/test-utils';

const FIXTURES_DIR = './tests/fixtures/basics';
const testFiles = glob.sync(`${FIXTURES_DIR}/**/*.src.js`);
Expand All @@ -15,8 +18,8 @@ describe('basics', () => {
testFiles.forEach(filename => {
const code = fs.readFileSync(filename, 'utf8');
it(
testUtils.formatSnapshotName(filename, FIXTURES_DIR),
testUtils.createSnapshotTestBlock(code)
formatSnapshotName(filename, FIXTURES_DIR),
createScopeSnapshotTestBlock(code)
);
});

Expand Down
9 changes: 6 additions & 3 deletions packages/parser/tests/lib/comments.ts
@@ -1,6 +1,9 @@
import fs from 'fs';
import glob from 'glob';
import * as testUtils from '../../tools/test-utils';
import {
createSnapshotTestBlock,
formatSnapshotName
} from '../tools/test-utils';
import { ParserOptions } from '../../src/parser-options';

const FIXTURES_DIR =
Expand All @@ -21,8 +24,8 @@ describe('Comments', () => {
}
};
it(
testUtils.formatSnapshotName(filename, FIXTURES_DIR),
testUtils.createSnapshotTestBlock(code, config)
formatSnapshotName(filename, FIXTURES_DIR),
createSnapshotTestBlock(code, config)
);
});
});
9 changes: 6 additions & 3 deletions packages/parser/tests/lib/javascript.ts
@@ -1,6 +1,9 @@
import fs from 'fs';
import glob from 'glob';
import * as testUtils from '../../tools/test-utils';
import {
createScopeSnapshotTestBlock,
formatSnapshotName
} from '../tools/test-utils';

const FIXTURES_DIR =
'../../node_modules/@typescript-eslint/shared-fixtures/fixtures/javascript';
Expand All @@ -14,8 +17,8 @@ describe('javascript', () => {
testFiles.forEach(filename => {
const code = fs.readFileSync(filename, 'utf8');
it(
testUtils.formatSnapshotName(filename, FIXTURES_DIR),
testUtils.createSnapshotTestBlock(code)
formatSnapshotName(filename, FIXTURES_DIR),
createScopeSnapshotTestBlock(code)
);
});
});
9 changes: 6 additions & 3 deletions packages/parser/tests/lib/jsx.ts
@@ -1,7 +1,10 @@
import fs from 'fs';
import glob from 'glob';
import filesWithKnownIssues from '../../../shared-fixtures/jsx-known-issues';
import * as testUtils from '../../tools/test-utils';
import {
createScopeSnapshotTestBlock,
formatSnapshotName
} from '../tools/test-utils';

const JSX_FIXTURES_DIR =
'../../node_modules/@typescript-eslint/shared-fixtures/fixtures/jsx';
Expand Down Expand Up @@ -33,8 +36,8 @@ describe('JSX', () => {
}
};
it(
testUtils.formatSnapshotName(filename, fixturesDir),
testUtils.createSnapshotTestBlock(code, config)
formatSnapshotName(filename, fixturesDir),
createScopeSnapshotTestBlock(code, config)
);
};
}
Expand Down
207 changes: 17 additions & 190 deletions packages/parser/tests/lib/scope-analysis.ts
@@ -1,220 +1,47 @@
import fs from 'fs';
import path from 'path';
import * as parser from '../../src/parser';

/** Reference resolver. */
class ReferenceResolver {
map: Map<any, any>;

constructor() {
this.map = new Map();
}

resolve(obj: any, properties: any) {
const resolved = Object.assign({ $id: this.map.size }, properties);
this.map.set(obj, resolved);
return resolved;
}

ref(obj: any) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}

const { map } = this;
return {
get $ref() {
return map.get(obj).$id;
}
};
}
}

/**
* Convert a given node object to JSON object.
* This saves only type and range to know what the node is.
* @param {ASTNode} node The AST node object.
* @returns {Object} The object that can be used for JSON.stringify.
*/
function nodeToJSON(node: any) {
if (!node) {
return node;
}

const { type, name, range } = node;
if (node.type === 'Identifier') {
return { type, name, range };
}
return { type, range };
}

/**
* Convert a given variable object to JSON object.
* @param {Variable} variable The eslint-scope's variable object.
* @param {ReferenceResolver} resolver The reference resolver.
* @returns {Object} The object that can be used for JSON.stringify.
*/
function variableToJSON(variable: any, resolver: any) {
const { name, eslintUsed } = variable;
const defs = variable.defs.map((d: any) => ({
type: d.type,
name: nodeToJSON(d.name),
node: nodeToJSON(d.node),
parent: nodeToJSON(d.parent)
}));
const identifiers = variable.identifiers.map(nodeToJSON);
const references = variable.references.map(resolver.ref, resolver);
const scope = resolver.ref(variable.scope);

return resolver.resolve(variable, {
name,
defs,
identifiers,
references,
scope,
eslintUsed
});
}

/**
* Convert a given reference object to JSON object.
* @param {Reference} reference The eslint-scope's reference object.
* @param {ReferenceResolver} resolver The reference resolver.
* @returns {Object} The object that can be used for JSON.stringify.
*/
function referenceToJSON(reference: any, resolver: any) {
const kind = `${reference.isRead() ? 'r' : ''}${
reference.isWrite() ? 'w' : ''
}`;
const from = resolver.ref(reference.from);
const identifier = nodeToJSON(reference.identifier);
const writeExpr = nodeToJSON(reference.writeExpr);
const resolved = resolver.ref(reference.resolved);

return resolver.resolve(reference, {
kind,
from,
identifier,
writeExpr,
resolved
});
}

/**
* Convert a given scope object to JSON object.
* @param {Scope} scope The eslint-scope's scope object.
* @param {ReferenceResolver} resolver The reference resolver.
* @returns {Object} The object that can be used for JSON.stringify.
*/
function scopeToJSON(scope: any, resolver = new ReferenceResolver()) {
const { type, functionExpressionScope, isStrict } = scope;
const block = nodeToJSON(scope.block);
const variables = scope.variables.map((v: any) =>
variableToJSON(v, resolver)
);
const references = scope.references.map((r: any) =>
referenceToJSON(r, resolver)
);
const variableMap = Array.from(scope.set.entries()).reduce(
(map: any, [name, variable]: any) => {
map[name] = resolver.ref(variable);
return map;
},
{}
);
const throughReferences = scope.through.map(resolver.ref, resolver);
const variableScope = resolver.ref(scope.variableScope);
const upperScope = resolver.ref(scope.upper);
const childScopes = scope.childScopes.map((c: any) =>
scopeToJSON(c, resolver)
);

return resolver.resolve(scope, {
type,
functionExpressionScope,
isStrict,
block,
variables,
references,
variableMap,
throughReferences,
variableScope,
upperScope,
childScopes
});
}
import { createScopeSnapshotTestBlock } from '../tools/test-utils';

describe('TypeScript scope analysis', () => {
const root = 'tests/fixtures/scope-analysis';
const fixturesDir = 'tests/fixtures/scope-analysis';
const files = fs
.readdirSync(root)
.map(filename => path.join(root, filename).replace(/\\/g, '/'));
.readdirSync(fixturesDir)
.map(filename => path.join(fixturesDir, filename).replace(/\\/g, '/'));

describe('sourceType: module', () => {
for (const filePath of files) {
it(filePath, () => {
const code = fs.readFileSync(filePath, 'utf8');
const { scopeManager } = parser.parseForESLint(code, {
const code = fs.readFileSync(filePath, 'utf8');
it(
filePath,
createScopeSnapshotTestBlock(code, {
loc: true,
range: true,
tokens: true,
sourceType: 'module',
ecmaFeatures: {
jsx: path.extname(filePath) === '.tsx'
}
});
const { globalScope } = scopeManager;

// Do the postprocess to test.
// https://github.com/eslint/eslint/blob/4fe328787dd02d7a1f6fc21167f6175c860825e3/lib/linter.js#L222
globalScope.through = globalScope.through.filter((reference: any) => {
const name = reference.identifier.name;
const variable = globalScope.set.get(name);
if (variable) {
reference.resolved = variable;
variable.references.push(reference);
return false;
}
return true;
});

const scopeTree = scopeToJSON(globalScope);
expect(scopeTree).toMatchSnapshot();
});
})
);
}
});

describe('sourceType: script', () => {
for (const filePath of files) {
it(filePath, () => {
const code = fs.readFileSync(filePath, 'utf8');
const { scopeManager } = parser.parseForESLint(code, {
const code = fs.readFileSync(filePath, 'utf8');

it(
filePath,
createScopeSnapshotTestBlock(code, {
loc: true,
range: true,
tokens: true,
sourceType: 'script',
ecmaFeatures: {
jsx: path.extname(filePath) === '.tsx'
}
});
const { globalScope } = scopeManager;

// Do the postprocess to test.
// https://github.com/eslint/eslint/blob/4fe328787dd02d7a1f6fc21167f6175c860825e3/lib/linter.js#L222
globalScope.through = globalScope.through.filter((reference: any) => {
const name = reference.identifier.name;
const variable = globalScope.set.get(name);
if (variable) {
reference.resolved = variable;
variable.references.push(reference);
return false;
}
return true;
});

const scopeTree = scopeToJSON(globalScope);
expect(scopeTree).toMatchSnapshot();
});
})
);
}
});
});
18 changes: 9 additions & 9 deletions packages/parser/tests/lib/services.ts
@@ -1,7 +1,11 @@
import path from 'path';
import fs from 'fs';
import glob from 'glob';
import * as testUtils from '../../tools/test-utils';
import {
createSnapshotTestBlock,
formatSnapshotName,
testServices
} from '../tools/test-utils';

//------------------------------------------------------------------------------
// Setup
Expand All @@ -28,15 +32,11 @@ describe('services', () => {
const code = fs.readFileSync(filename, 'utf8');
const config = createConfig(filename);
it(
testUtils.formatSnapshotName(filename, FIXTURES_DIR, '.ts'),
testUtils.createSnapshotTestBlock(code, config)
formatSnapshotName(filename, FIXTURES_DIR, '.ts'),
createSnapshotTestBlock(code, config)
);
it(`${testUtils.formatSnapshotName(
filename,
FIXTURES_DIR,
'.ts'
)} services`, () => {
testUtils.testServices(code, config);
it(`${formatSnapshotName(filename, FIXTURES_DIR, '.ts')} services`, () => {
testServices(code, config);
});
});
});
9 changes: 6 additions & 3 deletions packages/parser/tests/lib/tsx.ts
Expand Up @@ -2,7 +2,10 @@ import { Linter } from 'eslint';
import fs from 'fs';
import glob from 'glob';
import * as parser from '../../src/parser';
import * as testUtils from '../../tools/test-utils';
import {
createScopeSnapshotTestBlock,
formatSnapshotName
} from '../tools/test-utils';

const FIXTURES_DIR =
'../../node_modules/@typescript-eslint/shared-fixtures/fixtures/tsx';
Expand All @@ -22,8 +25,8 @@ describe('TSX', () => {
}
};
it(
testUtils.formatSnapshotName(filename, FIXTURES_DIR, '.tsx'),
testUtils.createSnapshotTestBlock(code, config)
formatSnapshotName(filename, FIXTURES_DIR, '.tsx'),
createScopeSnapshotTestBlock(code, config)
);
});

Expand Down

0 comments on commit 929189b

Please sign in to comment.