Skip to content

Commit 7f31a56

Browse files
author
roman.vasilev
committed
New: First release
1 parent 9c1f430 commit 7f31a56

File tree

11 files changed

+402
-0
lines changed

11 files changed

+402
-0
lines changed

.editorconfig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# http://editorconfig.org
2+
root = true
3+
4+
[*]
5+
indent_style = space
6+
indent_size = 4
7+
end_of_line = lf
8+
charset = utf-8
9+
trim_trailing_whitespace = true
10+
insert_final_newline = true
11+
12+
[*.md]
13+
trim_trailing_whitespace = false
14+
15+
[*.json]
16+
indent_size = 2

.eslintrc.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
const tslintConfigRulesDirectory = [
2+
'node_modules/tslint/lib/rules',
3+
// 'node_modules/tslint-clean-code/dist/src',
4+
// 'node_modules/tslint-microsoft-contrib',
5+
];
6+
const tslintConfigRules = Object.assign({},
7+
require('tslint/lib/configs/recommended').rules,
8+
// require('tslint-clean-code/recommended_ruleset').rules,
9+
// require('tslint-microsoft-contrib/recommended_ruleset').rules,
10+
{
11+
'member-access': false,
12+
'ordered-imports': false,
13+
'quotemark': false,
14+
'no-var-keyword': false,
15+
'object-literal-sort-keys': false,
16+
'no-console': false,
17+
'arrow-parens': false,
18+
'max-line-length': false,
19+
'object-literal-key-quotes': false,
20+
'no-shadowed-variable': false,
21+
'only-arrow-functions': false,
22+
'no-var-requires': false,
23+
'semicolon': false,
24+
'interface-over-type-literal': false,
25+
'align': false,
26+
'trailing-comma': false,
27+
'typedef': false,
28+
'newline-before-return': false,
29+
'interface-name': false,
30+
}
31+
);
32+
33+
module.exports = {
34+
'root': true,
35+
'env': {
36+
'es6': true,
37+
'node': true
38+
},
39+
'extends': [
40+
'eslint:recommended',
41+
'plugin:unicorn/recommended',
42+
],
43+
'parser': 'typescript-eslint-parser',
44+
'parserOptions': {
45+
'ecmaVersion': 2017,
46+
'sourceType': 'module'
47+
},
48+
'plugins': [
49+
'unicorn',
50+
'typescript',
51+
'import',
52+
'tslint',
53+
],
54+
'rules': {
55+
'no-undef': 0,
56+
'no-unused-vars': 0,
57+
'indent': 0,
58+
'unicorn/import-index': 0,
59+
'tslint/config': [1, {
60+
// tsconfigFile: 'tsconfig.json',
61+
rules: tslintConfigRules,
62+
rulesDirectory: tslintConfigRulesDirectory,
63+
}],
64+
'import/newline-after-import': 0,
65+
'import/no-duplicates': 1,
66+
'import/max-dependencies': [1, { 'max': 10 }],
67+
'quotes': [1, 'single', { 'allowTemplateLiterals': true }],
68+
'semi': [1, 'always'],
69+
}
70+
};

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/node_modules
2+
/.idea
3+
/.awcache
4+
/.vscode
5+
/.nyc_output
6+
*.log
7+
~*
8+
/dist/

.npmignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# .gitignore
2+
/node_modules
3+
/.idea
4+
/.awcache
5+
/.vscode
6+
/.nyc_output
7+
*.log
8+
~*
9+
# .npmignore
10+
/tsconfig.json
11+
/.eslintrc.js
12+
/.editorconfig

.npmrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
package-lock = false
2+
# save-exact = true

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
typescript-service
2+
===
3+
4+
5+
CHANGELOG
6+
---
7+
See [CHANGELOG.md](CHANGELOG.md)

package.json

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
{
2+
"name": "typescript-service",
3+
"version": "0.0.0-dev",
4+
"license": "MIT",
5+
"description": "",
6+
"main": "dist/index.js",
7+
"typings": "src/index.ts",
8+
"scripts": {
9+
"t": "npm run mocha -- src/*.spec.ts",
10+
"test": "npm run eslint && npm run tscheck && npm run t",
11+
"test:r": "npm run mocha -- src/*.spec.ts",
12+
"mocha": "node -r ts-node/register/transpile-only node_modules/mocha/bin/_mocha",
13+
"test:w": "npm run mocha -- --watch-extensions ts --watch src/**/*.spec.ts",
14+
"test:d": "node --inspect-brk -r ts-node/register/transpile-only node_modules/mocha/bin/_mocha --no-timeouts src/**/*.spec.ts",
15+
"tscheck": "echo tscheck... && tsc --noEmit",
16+
"tscheck:w": "npm run tscheck -- --watch",
17+
"tsclint": "tsc --noEmit --pretty --strict --forceConsistentCasingInFileNames --noImplicitReturns --noImplicitThis --noUnusedLocals --noUnusedParameters",
18+
"tsclint:w": "npm run tsclint -- --watch",
19+
"eslint": "eslint src --ext ts",
20+
"eslint:fix": "eslint src --ext \"ts\" --fix",
21+
"eslint:w": "chokidar \"src/**/*.ts\" --initial -c \"npm run eslint\"",
22+
"lint:w": "run-p tsclint:w eslint:w",
23+
"semantic-release": "semantic-release",
24+
"prepublishOnly": "npm run build",
25+
"build": "tsc",
26+
"prebuild": "npm run clean",
27+
"clean": "rimraf dist",
28+
"commit": "git-cz"
29+
},
30+
"dependencies": {},
31+
"devDependencies": {
32+
"@semantic-release/changelog": "^2.1.1",
33+
"@semantic-release/git": "^6.0.1",
34+
"@semantic-release/npm": "^3.3.4",
35+
"@types/mocha": "^5.2.3",
36+
"@types/node": "^10.5.1",
37+
"chokidar-cli": "^1.2.0",
38+
"conventional-changelog-eslint": "^3.0.0",
39+
"cz-adapter-eslint": "^0.1.2",
40+
"eslint": "^5.0.1",
41+
"eslint-plugin-import": "^2.13.0",
42+
"eslint-plugin-tslint": "^2.1.0",
43+
"eslint-plugin-typescript": "^0.12.0",
44+
"eslint-plugin-unicorn": "^4.0.3",
45+
"mocha": "^5.2.0",
46+
"npm-run-all": "^4.1.3",
47+
"rimraf": "^2.6.2",
48+
"semantic-release": "^15.6.0",
49+
"ts-node": "^7.0.0",
50+
"tslint": "^5.10.0",
51+
"tslint-clean-code": "^0.2.7",
52+
"tslint-microsoft-contrib": "^5.0.3",
53+
"typescript": "^2.9.2",
54+
"typescript-eslint-parser": "^16.0.1"
55+
},
56+
"engines": {
57+
"node": ">=6",
58+
"npm": ">=3"
59+
},
60+
"repository": {
61+
"type": "git",
62+
"url": "https://github.com/unlight/typescript-service.git"
63+
},
64+
"keywords": [],
65+
"release": {
66+
"generateNotes": {
67+
"preset": "eslint"
68+
},
69+
"analyzeCommits": {
70+
"preset": "eslint"
71+
},
72+
"verifyConditions": [
73+
"@semantic-release/changelog",
74+
"@semantic-release/github",
75+
"@semantic-release/npm",
76+
"@semantic-release/git"
77+
],
78+
"prepare": [
79+
"@semantic-release/changelog",
80+
"@semantic-release/npm",
81+
"@semantic-release/git"
82+
],
83+
"publish": [
84+
"@semantic-release/npm",
85+
"@semantic-release/github"
86+
],
87+
"success": [
88+
"@semantic-release/github"
89+
],
90+
"fail": [
91+
"@semantic-release/github"
92+
]
93+
},
94+
"config": {
95+
"commitizen": {
96+
"path": "./node_modules/cz-adapter-eslint"
97+
}
98+
}
99+
}

src/index.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import * as ts from 'typescript';
2+
import { readFileSync, existsSync } from 'fs';
3+
import { normalizeCompilerOptions } from './utils';
4+
5+
type createServiceOptions = {
6+
configFile: string;
7+
compilerOptions?: ts.CompilerOptions;
8+
};
9+
10+
export function createService({ compilerOptions, configFile }: createServiceOptions) {
11+
12+
const config = ts.readConfigFile(configFile, ts.sys.readFile);
13+
if (config.error) {
14+
throw new Error(ts.formatDiagnostics([config.error], {
15+
getCanonicalFileName: file => file,
16+
getCurrentDirectory: process.cwd,
17+
getNewLine: () => '\n',
18+
}));
19+
}
20+
21+
const compilationSettings: ts.CompilerOptions = normalizeCompilerOptions({
22+
...((config.config && config.config.compilerOptions) || {}),
23+
...(compilerOptions || {}),
24+
noEmit: true,
25+
sourceMap: false,
26+
inlineSources: false,
27+
inlineSourceMap: false,
28+
});
29+
30+
const files: ts.MapLike<{ version: number, snapshot: ts.IScriptSnapshot | undefined }> = {};
31+
32+
// Caches
33+
const fileExistsCache = Object.create(null);
34+
const readFileCache = Object.create(null);
35+
36+
// Create the language service host to allow the LS to communicate with the host
37+
const servicesHost: ts.LanguageServiceHost = {
38+
getScriptFileNames: () => {
39+
return Object.keys(files);
40+
},
41+
getScriptVersion: (fileName) => {
42+
return files[fileName] && String(files[fileName].version);
43+
},
44+
getScriptSnapshot(this: typeof servicesHost, fileName: string) {
45+
let fileRef = files[fileName];
46+
if (!fileRef) {
47+
files[fileName] = fileRef = { version: 0, snapshot: undefined };
48+
if (fileName === 'lib.d.ts') {
49+
fileName = require.resolve('typescript/lib/lib.d.ts').replace(/\\/g, '/');
50+
}
51+
}
52+
if (fileRef.snapshot === undefined) {
53+
const data = this.readFile && this.readFile(fileName);
54+
fileRef.snapshot = (data != null) ? ts.ScriptSnapshot.fromString(data) : undefined;
55+
}
56+
return fileRef.snapshot;
57+
},
58+
getCurrentDirectory: ts.sys.getCurrentDirectory,
59+
getCompilationSettings: () => compilationSettings,
60+
getDefaultLibFileName: (options) => {
61+
return ts.getDefaultLibFileName(options);
62+
},
63+
fileExists: (file) => {
64+
let result = fileExistsCache[file];
65+
if (result === undefined) {
66+
fileExistsCache[file] = result = existsSync(file);
67+
}
68+
return result;
69+
},
70+
readFile: (file) => {
71+
let result = readFileCache[file];
72+
if (result === undefined) {
73+
readFileCache[file] = result = readFileSync(file, 'utf8');
74+
}
75+
return result;
76+
},
77+
getDirectories: (directory) => {
78+
if (existsSync(directory)) {
79+
return ts.sys.getDirectories(directory);
80+
}
81+
return [];
82+
}
83+
};
84+
85+
// Adding libs
86+
(compilationSettings.lib || []).forEach(lib => {
87+
const fileName = require.resolve(`typescript/lib/lib.${lib}.d.ts`).replace(/\\/g, '/');
88+
files[fileName] = { version: 0, snapshot: servicesHost.getScriptSnapshot(fileName) };
89+
});
90+
91+
// Create the language service files
92+
const service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
93+
94+
return {
95+
update({ fileName, fileContent }: { fileName: string, fileContent: string }) {
96+
fileName = fileName.replace(/\\/g, '/');
97+
let fileRef = files[fileName];
98+
if (!fileRef) {
99+
files[fileName] = fileRef = { version: 0, snapshot: undefined };
100+
}
101+
fileRef.snapshot = ts.ScriptSnapshot.fromString(fileContent);
102+
fileRef.version++;
103+
104+
fileExistsCache[fileName] = true;
105+
readFileCache[fileName] = fileContent;
106+
},
107+
getDiagnostics(fileName: string) {
108+
const program = service.getProgram();
109+
const sourceFile = program.getSourceFile(fileName);
110+
return [
111+
...program.getSyntacticDiagnostics(sourceFile),
112+
...program.getSemanticDiagnostics(sourceFile),
113+
];
114+
},
115+
getProgram: () => service.getProgram(),
116+
};
117+
}

src/utils.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import * as ts from 'typescript';
2+
3+
export function normalizeCompilerOptions(options: ts.CompilerOptions = {}) {
4+
if (options.target) {
5+
options.target = toEnum(ts.ScriptTarget, options.target);
6+
}
7+
if (options.module) {
8+
options.module = toEnum(ts.ModuleKind, options.module);
9+
}
10+
if (options.moduleResolution) {
11+
if (String(options.moduleResolution).toLowerCase() === 'node') {
12+
options.moduleResolution = ts.ModuleResolutionKind.NodeJs;
13+
}
14+
options.moduleResolution = toEnum(ts.ModuleResolutionKind, options.moduleResolution);
15+
}
16+
return options;
17+
}
18+
19+
export function toEnum(collection: any, value: any) {
20+
let result = value;
21+
const valueLower = String(value).toLowerCase();
22+
const key = Object.keys(collection).find(value => String(value).toLowerCase() === valueLower);
23+
if (key !== undefined) {
24+
result = Number(collection[key]);
25+
if (Number.isNaN(result)) {
26+
result = value;
27+
}
28+
}
29+
return result;
30+
}

0 commit comments

Comments
 (0)