Skip to content

Commit

Permalink
refactor: port parse to typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
byCedric committed Jul 27, 2019
1 parent 6332d97 commit 46596a3
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 90 deletions.
31 changes: 5 additions & 26 deletions @commitlint/parse/package.json
Expand Up @@ -3,35 +3,13 @@
"version": "8.1.0",
"description": "Lint your commit messages",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib/"
],
"scripts": {
"build": "cross-env NODE_ENV=production babel src --out-dir lib --source-maps",
"deps": "dep-check",
"pkg": "pkg-check",
"start": "concurrently \"ava -c 4 --verbose --watch\" \"yarn run watch\"",
"test": "ava -c 4 --verbose",
"watch": "babel src --out-dir lib --watch --source-maps"
},
"ava": {
"files": [
"src/**/*.test.js",
"!lib/**/*"
],
"source": [
"src/**/*.js",
"!lib/**/*"
],
"babel": "inherit",
"require": [
"babel-register"
]
},
"babel": {
"presets": [
"babel-preset-commitlint"
]
"pkg": "pkg-check"
},
"engines": {
"node": ">=4"
Expand All @@ -58,13 +36,14 @@
"devDependencies": {
"@commitlint/test": "8.0.0",
"@commitlint/utils": "^8.1.0",
"ava": "0.22.0",
"@types/lodash": "^4.14.136",
"babel-cli": "6.26.0",
"babel-preset-commitlint": "^8.0.0",
"babel-register": "6.26.0",
"concurrently": "3.6.1",
"cross-env": "5.1.1",
"import-from": "3.0.0"
"import-from": "3.0.0",
"typescript": "^3.5.3"
},
"dependencies": {
"conventional-changelog-angular": "^1.3.3",
Expand Down
@@ -1,40 +1,40 @@
import importFrom from 'import-from';
import test from 'ava';
import parse from '.';

test('throws when called without params', async t => {
const error = await t.throws(parse());
t.is(error.message, 'Expected a raw commit');
test('throws when called without params', () => {
expect(parse()).rejects.toThrowError('Expected a raw commit');
});

test('throws when called with empty message', async t => {
const error = await t.throws(parse());
t.is(error.message, 'Expected a raw commit');
test('throws when called with empty message', () => {
expect(parse()).rejects.toThrowError('Expected a raw commit');
});

test('returns object with raw message', async t => {
test('returns object with raw message', async () => {
const message = 'type(scope): subject';
const actual = await parse(message);
t.is(actual.raw, message);

expect(actual).toHaveProperty('raw', message);
});

test('calls parser with message and passed options', async t => {
test('calls parser with message and passed options', async () => {
const message = 'message';

await parse(message, m => {
t.is(message, m);
expect.assertions(1);
await parse(message, (m: string) => {
expect(m).toBe(message);
return {};
});
});

test('passes object up from parser function', async t => {
test('passes object up from parser function', async () => {
const message = 'message';
const result = {};
const actual = await parse(message, () => result);
t.is(actual, result);

expect(actual).toBe(result);
});

test('returns object with expected keys', async t => {
test('returns object with expected keys', async () => {
const message = 'message';
const actual = await parse(message);
const expected = {
Expand All @@ -51,10 +51,11 @@ test('returns object with expected keys', async t => {
subject: null,
type: null
};
t.deepEqual(actual, expected);

expect(actual).toMatchObject(expected);
});

test('uses angular grammar', async t => {
test('uses angular grammar', async () => {
const message = 'type(scope): subject';
const actual = await parse(message);
const expected = {
Expand All @@ -71,14 +72,15 @@ test('uses angular grammar', async t => {
subject: 'subject',
type: 'type'
};
t.deepEqual(actual, expected);

expect(actual).toMatchObject(expected);
});

test('uses custom opts parser', async t => {
test('uses custom opts parser', async () => {
const message = 'type(scope)-subject';
const changelogOpts = await importFrom(
process.cwd(),
'./fixtures/parser-preset/conventional-changelog-custom'
const changelogOpts: any = await importFrom(
__dirname,
'../fixtures/parser-preset/conventional-changelog-custom.js'
);
const actual = await parse(message, undefined, changelogOpts.parserOpts);
const expected = {
Expand All @@ -95,10 +97,11 @@ test('uses custom opts parser', async t => {
subject: 'subject',
type: 'type'
};
t.deepEqual(actual, expected);

expect(actual).toMatchObject(expected);
});

test('does not merge array properties with custom opts', async t => {
test('does not merge array properties with custom opts', async () => {
const message = 'type: subject';
const actual = await parse(message, undefined, {
headerPattern: /^(.*):\s(.*)$/,
Expand All @@ -117,54 +120,59 @@ test('does not merge array properties with custom opts', async t => {
subject: 'subject',
type: 'type'
};
t.deepEqual(actual, expected);

expect(actual).toMatchObject(expected);
});

test('supports scopes with /', async t => {
test('supports scopes with /', async () => {
const message = 'type(some/scope): subject';
const actual = await parse(message);
t.is(actual.scope, 'some/scope');
t.is(actual.subject, 'subject');

expect(actual.scope).toBe('some/scope');
expect(actual.subject).toBe('subject');
});

test('supports scopes with / and empty parserOpts', async t => {
test('supports scopes with / and empty parserOpts', async () => {
const message = 'type(some/scope): subject';
const actual = await parse(message, undefined, {});
t.is(actual.scope, 'some/scope');
t.is(actual.subject, 'subject');

expect(actual.scope).toBe('some/scope');
expect(actual.subject).toBe('subject');
});

test('ignores comments', async t => {
test('ignores comments', async () => {
const message = 'type(some/scope): subject\n# some comment';
const changelogOpts = await importFrom(
const changelogOpts: any = await importFrom(
process.cwd(),
'conventional-changelog-angular'
);
const opts = Object.assign({}, changelogOpts.parserOpts, {
commentChar: '#'
});
const actual = await parse(message, undefined, opts);
t.is(actual.body, null);
t.is(actual.footer, null);
t.is(actual.subject, 'subject');

expect(actual.body).toBe(null);
expect(actual.footer).toBe(null);
expect(actual.subject).toBe('subject');
});

test('registers inline #', async t => {
test('registers inline #', async () => {
const message =
'type(some/scope): subject #reference\n# some comment\nthings #reference';
const changelogOpts = await importFrom(
const changelogOpts: any = await importFrom(
process.cwd(),
'conventional-changelog-angular'
);
const opts = Object.assign({}, changelogOpts.parserOpts, {
commentChar: '#'
});
const actual = await parse(message, undefined, opts);
t.is(actual.subject, 'subject #reference');
t.is(actual.body, 'things #reference');

expect(actual.subject).toBe('subject #reference');
expect(actual.body).toBe('things #reference');
});

test('parses references leading subject', async t => {
test('parses references leading subject', async () => {
const message = '#1 some subject';
const opts = await importFrom(
process.cwd(),
Expand All @@ -173,17 +181,18 @@ test('parses references leading subject', async t => {
const {
references: [actual]
} = await parse(message, undefined, opts);
t.is(actual.issue, '1');

expect(actual.issue).toBe('1');
});

test('parses custom references', async t => {
test('parses custom references', async () => {
const message = '#1 some subject PREFIX-2';
const {references} = await parse(message, undefined, {
issuePrefixes: ['PREFIX-']
});

t.falsy(references.find(ref => ref.issue === '1'));
t.deepEqual(references.find(ref => ref.issue === '2'), {
expect(references.find((ref: any) => ref.issue === '1')).toBeFalsy();
expect(references.find((ref: any) => ref.issue === '2')).toMatchObject({
action: null,
issue: '2',
owner: null,
Expand All @@ -193,44 +202,44 @@ test('parses custom references', async t => {
});
});

test('uses permissive default regex without parser opts', async t => {
test('uses permissive default regex without parser opts', async () => {
const message = 'chore(component,demo): bump';
const actual = await parse(message);

t.is(actual.scope, 'component,demo');
expect(actual.scope).toBe('component,demo');
});

test('uses permissive default regex with other parser opts', async t => {
test('uses permissive default regex with other parser opts', async () => {
const message = 'chore(component,demo): bump';
const actual = await parse(message, undefined, {commentChar: '#'});

t.is(actual.scope, 'component,demo');
expect(actual.scope).toBe('component,demo');
});

test('uses restrictive default regex in passed parser opts', async t => {
test('uses restrictive default regex in passed parser opts', async () => {
const message = 'chore(component,demo): bump';
const actual = await parse(message, undefined, {
headerPattern: /^(\w*)(?:\(([a-z]*)\))?: (.*)$/
});

t.is(actual.subject, null);
t.is(actual.scope, null);
expect(actual.subject).toBe(null);
expect(actual.scope).toBe(null);
});

test('works with chinese scope by default', async t => {
test('works with chinese scope by default', async () => {
const message = 'fix(面试评价): 测试';
const actual = await parse(message, undefined, {commentChar: '#'});

t.not(actual.subject, null);
t.not(actual.scope, null);
expect(actual.subject).not.toBe(null);
expect(actual.scope).not.toBe(null);
});

test('does not work with chinese scopes with incompatible pattern', async t => {
test('does not work with chinese scopes with incompatible pattern', async () => {
const message = 'fix(面试评价): 测试';
const actual = await parse(message, undefined, {
headerPattern: /^(\w*)(?:\(([a-z]*)\))?: (.*)$/
});

t.is(actual.subject, null);
t.is(actual.scope, null);
expect(actual.subject).toBe(null);
expect(actual.scope).toBe(null);
});
@@ -1,10 +1,15 @@
import {sync} from 'conventional-commits-parser';
import defaultChangelogOpts from 'conventional-changelog-angular';
import {isArray, mergeWith} from 'lodash';

const {sync} = require('conventional-commits-parser');
const defaultChangelogOpts = require('conventional-changelog-angular');

export default parse;

async function parse(message, parser = sync, parserOpts = undefined) {
async function parse(
message?: any,
parser: any = sync,
parserOpts: any = undefined
) {
const defaultOpts = (await defaultChangelogOpts).parserOpts;
const parsed = parser(
message,
Expand Down
15 changes: 15 additions & 0 deletions @commitlint/parse/tsconfig.json
@@ -0,0 +1,15 @@
{
"extends": "../../tsconfig.shared.json",
"compilerOptions": {
"composite": true,
"rootDir": "./src",
"outDir": "./lib"
},
"include": [
"./src"
],
"exclude": [
"./src/**/*.test.ts",
"./lib/**/*"
]
}
3 changes: 2 additions & 1 deletion tsconfig.json
Expand Up @@ -7,8 +7,9 @@
{ "path": "@commitlint/execute-rule" },
{ "path": "@commitlint/format" },
{ "path": "@commitlint/is-ignored" },
{ "path": "@commitlint/parse" },
{ "path": "@commitlint/resolve-extends" },
{ "path": "@commitlint/to-lines" },
{ "path": "@commitlint/top-level" },
]
}
}
4 changes: 2 additions & 2 deletions yarn.lock
Expand Up @@ -1285,7 +1285,7 @@
dependencies:
"@types/jest-diff" "*"

"@types/lodash@4.14.136":
"@types/lodash@4.14.136", "@types/lodash@^4.14.136":
version "4.14.136"
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.136.tgz#413e85089046b865d960c9ff1d400e04c31ab60f"
integrity sha512-0GJhzBdvsW2RUccNHOBkabI8HZVdOXmXbXhuKlDEd5Vv12P7oAVGfomGp3Ne21o5D/qu1WmthlNKFaoZJJeErA==
Expand Down Expand Up @@ -10913,7 +10913,7 @@ typedarray@^0.0.6:
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=

typescript@3.5.3:
typescript@3.5.3, typescript@^3.5.3:
version "3.5.3"
resolved "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
Expand Down

0 comments on commit 46596a3

Please sign in to comment.