New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@fimbul/wotan

Package Overview
Dependencies
Maintainers
2
Versions
180
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fimbul/wotan - npm Package Compare versions

Comparing version 0.24.0-dev.20210214 to 0.24.0-dev.20210216

src/services/default/content-hasher.d.ts

1

index.d.ts

@@ -5,2 +5,3 @@ export * from '@fimbul/ymir';

export * from './src/services/default/configuration-provider';
export * from './src/services/default/content-hasher';
export * from './src/services/default/deprecation-handler';

@@ -7,0 +8,0 @@ export * from './src/services/default/directory-service';

@@ -9,2 +9,3 @@ "use strict";

tslib_1.__exportStar(require("./src/services/default/configuration-provider"), exports);
tslib_1.__exportStar(require("./src/services/default/content-hasher"), exports);
tslib_1.__exportStar(require("./src/services/default/deprecation-handler"), exports);

@@ -11,0 +12,0 @@ tslib_1.__exportStar(require("./src/services/default/directory-service"), exports);

@@ -14,2 +14,3 @@ import * as ts from 'typescript';

private findingsForFile;
private oldState;
getExternalFiles?: () => string[];

@@ -22,3 +23,4 @@ constructor(config: Record<string, unknown>, project: import('typescript/lib/tsserverlibrary').server.Project, serverHost: import('typescript/lib/tsserverlibrary').server.ServerHost, languageService: ts.LanguageService, require: (id: string) => {}, log: (message: string) => void);

getSupportedCodeFixes(fixes: string[]): string[];
cleanupSemanticCache(): void;
dispose(): void;
}

75

language-service/index.js

@@ -19,2 +19,4 @@ "use strict";

const minimatch_1 = require("minimatch");
const program_state_1 = require("../src/services/program-state");
const config_hash_1 = require("../src/config-hash");
exports.version = '1';

@@ -34,2 +36,3 @@ class LanguageServiceInterceptor {

this.findingsForFile = new WeakMap();
this.oldState = undefined;
}

@@ -41,27 +44,28 @@ updateConfig(config) {

const program = this.languageService.getProgram();
if (program === undefined)
return diagnostics;
const file = program.getSourceFile(fileName);
if (file === undefined) {
this.log(`file ${fileName} is not included in the Program`);
return diagnostics;
}
else {
this.log(`started linting ${fileName}`);
const findings = this.getFindings(file, program);
this.findingsForFile.set(file, findings);
diagnostics = diagnostics.concat(findings.map((finding) => ({
file,
category: finding.severity === 'error'
? this.config.displayErrorsAsWarnings
? ts.DiagnosticCategory.Warning
: ts.DiagnosticCategory.Error
: finding.severity === 'warning'
? ts.DiagnosticCategory.Warning
: ts.DiagnosticCategory.Suggestion,
code: finding.ruleName,
source: 'wotan',
messageText: finding.message,
start: finding.start.position,
length: finding.end.position - finding.start.position,
})));
this.log(`finished linting ${fileName} with ${findings.length} findings`);
}
this.log(`started linting ${fileName}`);
const findings = this.getFindings(file, program);
this.findingsForFile.set(file, findings);
diagnostics = diagnostics.concat(findings.map((finding) => ({
file,
category: finding.severity === 'error'
? this.config.displayErrorsAsWarnings
? ts.DiagnosticCategory.Warning
: ts.DiagnosticCategory.Error
: finding.severity === 'warning'
? ts.DiagnosticCategory.Warning
: ts.DiagnosticCategory.Suggestion,
code: finding.ruleName,
source: 'wotan',
messageText: finding.message,
start: finding.start.position,
length: finding.end.position - finding.start.position,
})));
this.log(`finished linting ${fileName} with ${findings.length} findings`);
return diagnostics;

@@ -93,2 +97,9 @@ }

container.load(this.loadPluginModule(module, globalConfigDir, globalOptions));
container.bind(ymir_1.StatePersistence).toConstantValue({
loadState: () => this.oldState,
saveState: (_, state) => this.oldState = state,
});
container.bind(ymir_1.ContentId).toConstantValue({
forFile: (fileName) => this.project.getScriptVersion(fileName),
});
container.bind(ymir_1.FileSystem).toConstantValue(new ProjectFileSystem(this.project));

@@ -138,4 +149,3 @@ container.bind(ymir_1.DirectoryService).toConstantValue({

return [];
const linter = container.get(linter_1.Linter);
return linter.lintFile(file, effectiveConfig, program, {
const linterOptions = {
reportUselessDirectives: globalConfig.reportUselessDirectives

@@ -146,3 +156,15 @@ ? globalConfig.reportUselessDirectives === true

: undefined,
});
};
const programState = container.get(program_state_1.ProgramStateFactory).create(program, this.project, this.project.projectName);
const configHash = config_hash_1.createConfigHash(effectiveConfig, linterOptions);
const cached = programState.getUpToDateResult(file.fileName, configHash);
if (cached !== undefined) {
this.log('Using cached results');
return cached;
}
const linter = container.get(linter_1.Linter);
const result = linter.lintFile(file, effectiveConfig, program, linterOptions);
programState.setFileResult(file.fileName, configHash, result);
programState.save();
return result;
}

@@ -164,4 +186,7 @@ loadPluginModule(moduleName, basedir, options) {

}
cleanupSemanticCache() {
this.findingsForFile = new WeakMap();
this.oldState = undefined;
}
dispose() {
// TODO clean up after ourselves
return this.languageService.dispose();

@@ -168,0 +193,0 @@ }

{
"name": "@fimbul/wotan",
"version": "0.24.0-dev.20210214",
"version": "0.24.0-dev.20210216",
"description": "Pluggable TypeScript and JavaScript linter",

@@ -44,4 +44,4 @@ "bin": "bin/main.js",

"dependencies": {
"@fimbul/mimir": "0.24.0-dev.20210214",
"@fimbul/ymir": "0.24.0-dev.20210214",
"@fimbul/mimir": "0.24.0-dev.20210216",
"@fimbul/ymir": "0.24.0-dev.20210216",
"bind-decorator": "^1.0.11",

@@ -48,0 +48,0 @@ "chalk": "^4.0.0",

@@ -19,2 +19,3 @@ "use strict";

const state_persistence_1 = require("../services/default/state-persistence");
const content_hasher_1 = require("../services/default/content-hasher");
function createDefaultModule() {

@@ -50,2 +51,4 @@ return new inversify_1.ContainerModule((bind, _unbind, isBound) => {

bind(ymir_1.StatePersistence).to(state_persistence_1.DefaultStatePersistence);
if (!isBound(ymir_1.ContentId))
bind(ymir_1.ContentId).to(content_hasher_1.ContentHasher);
});

@@ -52,0 +55,0 @@ }

@@ -92,4 +92,6 @@ "use strict";

var _a;
const result = new Map();
if (this.program.getSourceFile(file) === undefined)
return result;
(_a = this.state) !== null && _a !== void 0 ? _a : (this.state = this.buildState());
const result = new Map();
{

@@ -96,0 +98,0 @@ const augmentations = this.state.moduleAugmentations.get(file);

import * as ts from 'typescript';
import { DependencyResolver, DependencyResolverFactory, DependencyResolverHost } from './dependency-resolver';
import { Finding, StatePersistence } from '@fimbul/ymir';
import { ContentId, Finding, StatePersistence } from '@fimbul/ymir';
export interface ProgramState {

@@ -13,3 +13,4 @@ update(program: ts.Program, updatedFile: string): void;

private statePersistence;
constructor(resolverFactory: DependencyResolverFactory, statePersistence: StatePersistence);
private contentId;
constructor(resolverFactory: DependencyResolverFactory, statePersistence: StatePersistence, contentId: ContentId);
create(program: ts.Program, host: ProgramStateHost & DependencyResolverHost, tsconfigPath: string): ProgramStateImpl;

@@ -24,10 +25,10 @@ }

private statePersistence;
private contentId;
private project;
private projectDirectory;
private caseSensitive;
private getCanonicalFileName;
private canonicalProjectDirectory;
private optionsHash;
private assumeChangesOnlyAffectDirectDependencies;
private fileHashes;
private contentIds;
private fileResults;

@@ -38,8 +39,9 @@ private relativePathNames;

private dependenciesUpToDate;
constructor(host: ProgramStateHost, program: ts.Program, resolver: DependencyResolver, statePersistence: StatePersistence, project: string);
private contentIdHost;
constructor(host: ProgramStateHost, program: ts.Program, resolver: DependencyResolver, statePersistence: StatePersistence, contentId: ContentId, project: string);
/** get old state if global files didn't change */
private tryReuseOldState;
update(program: ts.Program, updatedFile: string): void;
private getFileHash;
private computeFileHash;
private getContentId;
private computeContentId;
private getRelativePath;

@@ -53,3 +55,3 @@ private makeRelativePath;

private aggregate;
private sortByHash;
private sortById;
private lookupFileIndex;

@@ -56,0 +58,0 @@ private remapFileNames;

@@ -16,8 +16,9 @@ "use strict";

let ProgramStateFactory = class ProgramStateFactory {
constructor(resolverFactory, statePersistence) {
constructor(resolverFactory, statePersistence, contentId) {
this.resolverFactory = resolverFactory;
this.statePersistence = statePersistence;
this.contentId = contentId;
}
create(program, host, tsconfigPath) {
return new ProgramStateImpl(host, program, this.resolverFactory.create(host, program), this.statePersistence, tsconfigPath);
return new ProgramStateImpl(host, program, this.resolverFactory.create(host, program), this.statePersistence, this.contentId, tsconfigPath);
}

@@ -27,3 +28,5 @@ };

inversify_1.injectable(),
tslib_1.__metadata("design:paramtypes", [dependency_resolver_1.DependencyResolverFactory, ymir_1.StatePersistence])
tslib_1.__metadata("design:paramtypes", [dependency_resolver_1.DependencyResolverFactory,
ymir_1.StatePersistence,
ymir_1.ContentId])
], ProgramStateFactory);

@@ -34,3 +37,3 @@ exports.ProgramStateFactory = ProgramStateFactory;

class ProgramStateImpl {
constructor(host, program, resolver, statePersistence, project) {
constructor(host, program, resolver, statePersistence, contentId, project) {
this.host = host;

@@ -40,13 +43,17 @@ this.program = program;

this.statePersistence = statePersistence;
this.contentId = contentId;
this.project = project;
this.projectDirectory = utils_1.unixifyPath(path.dirname(this.project));
this.caseSensitive = this.host.useCaseSensitiveFileNames();
this.getCanonicalFileName = this.caseSensitive ? (f) => f : (f) => f.toLowerCase();
this.canonicalProjectDirectory = this.getCanonicalFileName(this.projectDirectory);
this.canonicalProjectDirectory = this.caseSensitive ? this.projectDirectory : this.projectDirectory.toLowerCase();
this.optionsHash = computeCompilerOptionsHash(this.program.getCompilerOptions(), this.projectDirectory);
this.assumeChangesOnlyAffectDirectDependencies = tsutils_1.isCompilerOptionEnabled(this.program.getCompilerOptions(), 'assumeChangesOnlyAffectDirectDependencies');
this.fileHashes = new Map();
this.contentIds = new Map();
this.fileResults = new Map();
this.relativePathNames = new Map();
this.recheckOldState = true;
// TODO this can be removed once ProjectHost correctly reflects applied fixed in readFile
this.contentIdHost = {
readFile: (f) => { var _a; return (_a = this.program.getSourceFile(f)) === null || _a === void 0 ? void 0 : _a.text; },
};
const oldState = this.statePersistence.loadState(project);

@@ -70,8 +77,8 @@ if ((oldState === null || oldState === void 0 ? void 0 : oldState.v) !== STATE_VERSION || oldState.ts !== ts.version || oldState.options !== this.optionsHash) {

return this[oldStateSymbol] = undefined;
const globalFilesWithHash = this.sortByHash(filesAffectingGlobalScope);
for (let i = 0; i < globalFilesWithHash.length; ++i) {
const globalFilesWithId = this.sortById(filesAffectingGlobalScope);
for (let i = 0; i < globalFilesWithId.length; ++i) {
const index = oldState.global[i];
if (globalFilesWithHash[i].hash !== oldState.files[index].hash ||
if (globalFilesWithId[i].id !== oldState.files[index].id ||
!this.assumeChangesOnlyAffectDirectDependencies &&
!this.fileDependenciesUpToDate(globalFilesWithHash[i].fileName, index, oldState))
!this.fileDependenciesUpToDate(globalFilesWithId[i].fileName, index, oldState))
return this[oldStateSymbol] = undefined;

@@ -85,12 +92,11 @@ }

this.resolver.update(program, updatedFile);
this.fileHashes.delete(updatedFile);
this.contentIds.delete(updatedFile);
this.recheckOldState = true;
this.dependenciesUpToDate.fill(0 /* Unknown */);
}
getFileHash(file) {
// TODO move hashing to a separate service
return utils_1.resolveCachedResult(this.fileHashes, file, this.computeFileHash);
getContentId(file) {
return utils_1.resolveCachedResult(this.contentIds, file, this.computeContentId);
}
computeFileHash(file) {
return '' + utils_1.djb2(this.program.getSourceFile(file).text);
computeContentId(file) {
return this.contentId.forFile(file, this.contentIdHost);
}

@@ -101,3 +107,3 @@ getRelativePath(fileName) {

makeRelativePath(fileName) {
return utils_1.unixifyPath(path.relative(this.canonicalProjectDirectory, this.getCanonicalFileName(fileName)));
return utils_1.unixifyPath(path.relative(this.canonicalProjectDirectory, this.caseSensitive ? fileName : fileName.toLowerCase()));
}

@@ -114,3 +120,3 @@ getUpToDateResult(fileName, configHash) {

old.config !== configHash ||
old.hash !== this.getFileHash(fileName) ||
old.id !== this.getContentId(fileName) ||
!this.fileDependenciesUpToDate(fileName, index, oldState))

@@ -139,3 +145,3 @@ return;

const index = this.lookupFileIndex(fileName, oldState);
if (index === undefined || oldState.files[index].hash !== this.getFileHash(fileName))
if (index === undefined || oldState.files[index].id !== this.getContentId(fileName))
return false;

@@ -203,12 +209,12 @@ switch (this.dependenciesUpToDate[index]) {

return markAsOutdated(parents, index, cycles, this.dependenciesUpToDate);
const newDepsWithHash = this.sortByHash(newDeps);
for (let i = 0; i < newDepsWithHash.length; ++i) {
const newDepsWithId = this.sortById(newDeps);
for (let i = 0; i < newDepsWithId.length; ++i) {
const oldDepState = oldState.files[oldDeps[i]];
if (newDepsWithHash[i].hash !== oldDepState.hash)
if (newDepsWithId[i].id !== oldDepState.id)
return markAsOutdated(parents, index, cycles, this.dependenciesUpToDate);
if (!this.assumeChangesOnlyAffectDirectDependencies && fileName !== newDepsWithHash[i].fileName) {
if (!this.assumeChangesOnlyAffectDirectDependencies && fileName !== newDepsWithId[i].fileName) {
const indexInQueue = parents.indexOf(oldDeps[i]);
if (indexInQueue === -1) {
// no circular dependency
fileNameQueue.push(newDepsWithHash[i].fileName);
fileNameQueue.push(newDepsWithId[i].fileName);
indexQueue.push(oldDeps[i]);

@@ -277,5 +283,16 @@ ++childCount;

aggregate() {
const additionalFiles = new Set();
const oldState = this.tryReuseOldState();
const sourceFiles = this.program.getSourceFiles();
const lookup = {};
const mapToIndex = ({ fileName }) => lookup[this.relativePathNames.get(fileName)];
const mapToIndex = ({ fileName }) => {
const relativeName = this.getRelativePath(fileName);
let index = lookup[relativeName];
if (index === undefined) {
index = sourceFiles.length + additionalFiles.size;
additionalFiles.add(fileName);
lookup[relativeName] = index;
}
return index;
};
const mapDependencies = (dependencies) => {

@@ -288,7 +305,6 @@ if (dependencies.size === 0)

? null
: this.sortByHash(Array.from(new Set(f))).map(mapToIndex);
: this.sortById(Array.from(new Set(f))).map(mapToIndex);
return result;
};
const files = [];
const sourceFiles = this.program.getSourceFiles();
for (let i = 0; i < sourceFiles.length; ++i)

@@ -312,6 +328,8 @@ lookup[this.getRelativePath(sourceFiles[i].fileName)] = i;

...results,
hash: this.getFileHash(file.fileName),
id: this.getContentId(file.fileName),
dependencies: mapDependencies(this.resolver.getDependencies(file.fileName)),
});
}
for (const additional of additionalFiles)
files.push({ id: this.getContentId(additional) });
return {

@@ -323,10 +341,10 @@ files,

cs: this.caseSensitive,
global: this.sortByHash(this.resolver.getFilesAffectingGlobalScope()).map(mapToIndex),
global: this.sortById(this.resolver.getFilesAffectingGlobalScope()).map(mapToIndex),
options: this.optionsHash,
};
}
sortByHash(fileNames) {
sortById(fileNames) {
return fileNames
.map((f) => ({ fileName: f, hash: this.getFileHash(f) }))
.sort(compareHashKey);
.map((f) => ({ fileName: f, id: this.getContentId(f) }))
.sort(compareId);
}

@@ -354,3 +372,3 @@ lookupFileIndex(fileName, oldState) {

tslib_1.__metadata("design:returntype", void 0)
], ProgramStateImpl.prototype, "computeFileHash", null);
], ProgramStateImpl.prototype, "computeContentId", null);
tslib_1.__decorate([

@@ -419,4 +437,4 @@ bind_decorator_1.default,

}
function compareHashKey(a, b) {
return +(a.hash >= b.hash) - +(a.hash <= b.hash);
function compareId(a, b) {
return +(a.id >= b.id) - +(a.id <= b.id);
}

@@ -423,0 +441,0 @@ const compilerOptionKinds = {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc