@rehearsal/service
Advanced tools
Comparing version 2.0.0-beta to 2.0.0
@@ -1,5 +0,6 @@ | ||
import * as ts from 'typescript'; | ||
import ts from 'typescript'; | ||
import { DiagnosticSeverity, type Diagnostic, type Range, type CodeAction } from 'vscode-languageserver'; | ||
import { Service } from './rehearsal-service.js'; | ||
import type { GlintLanguageServer, TransformManager } from '@glint/core'; | ||
import type { DiagnosticWithLocation } from 'typescript'; | ||
type TS = typeof import('typescript'); | ||
@@ -38,2 +39,3 @@ export type GlintCore = typeof import('@glint/core'); | ||
getDiagnostics(fileName: string): ts.DiagnosticWithLocation[]; | ||
getAdditionalDiagnostics(fileName: string): DiagnosticWithLocation[]; | ||
convertLSPDiagnosticToTs(fileName: string, diagnostic: Diagnostic): ts.DiagnosticWithLocation; | ||
@@ -40,0 +42,0 @@ convertTsDiagnosticToLSP(diagnostic: ts.DiagnosticWithLocation): Diagnostic; |
@@ -5,4 +5,6 @@ // This is disabled because vscode-uri is a commonjs module, which causes TS and Eslint to disagree | ||
import VSCodeURI from 'vscode-uri'; | ||
import ts from 'typescript'; | ||
import { DiagnosticSeverity, } from 'vscode-languageserver'; | ||
import { isGlintFile } from './glint-utils.js'; | ||
const { forEachChild, isFunctionDeclaration, isMethodDeclaration } = ts; | ||
export class GlintService { | ||
@@ -41,6 +43,6 @@ constructor(glintCore, glintProjectDir) { | ||
if (isGlintFile(this, fileName)) { | ||
return createSyntheticSourceFile(this.ts, { | ||
filename: fileName, | ||
contents: this.getFileText(fileName), | ||
}); | ||
return ts.createSourceFile(fileName, this.getFileText(fileName), ts.ScriptTarget.Latest, | ||
// This parameter makes SourceFile object similar to one that TS program returns | ||
// Helps each Node to have access to a source file content + working getStart(), getText(), etc. methods | ||
true); | ||
} | ||
@@ -61,7 +63,28 @@ else { | ||
getDiagnostics(fileName) { | ||
const diagnostics = this.service.getDiagnostics(fileName); | ||
return diagnostics.map((diagnostic) => { | ||
return this.convertLSPDiagnosticToTs(fileName, diagnostic); | ||
}); | ||
const diagnostics = this.service | ||
.getDiagnostics(fileName) | ||
.map((diagnostic) => this.convertLSPDiagnosticToTs(fileName, diagnostic)); | ||
return [...diagnostics, ...this.getAdditionalDiagnostics(fileName)]; | ||
} | ||
getAdditionalDiagnostics(fileName) { | ||
const sourceFile = this.getSourceFile(fileName); | ||
const diagnostics = []; | ||
const visitEveryNode = (node) => { | ||
if ((isFunctionDeclaration(node) || isMethodDeclaration(node)) && node.name && !node.type) { | ||
diagnostics.push({ | ||
file: sourceFile, | ||
start: node.getStart(), | ||
length: node.getEnd() - node.getStart(), | ||
category: ts.DiagnosticCategory.Suggestion, | ||
code: 7050, | ||
messageText: (isFunctionDeclaration(node) ? `Function` : `Method`) + | ||
` '${node.name.getText()}' lacks a return-type annotation.`, | ||
}); | ||
return undefined; | ||
} | ||
return forEachChild(node, visitEveryNode); | ||
}; | ||
visitEveryNode(sourceFile); | ||
return diagnostics; | ||
} | ||
convertLSPDiagnosticToTs(fileName, diagnostic) { | ||
@@ -163,8 +186,2 @@ const sourceFile = this.getSourceFile(fileName); | ||
} | ||
function createSyntheticSourceFile(ts, source) { | ||
return Object.assign(ts.createSourceFile(source.filename, source.contents, ts.ScriptTarget.Latest), { | ||
text: source.contents, | ||
end: source.contents.length, | ||
}); | ||
} | ||
//# sourceMappingURL=glint-service.js.map |
import { RehearsalService } from './rehearsal-service.js'; | ||
import type { GlintService } from './glint-service.js'; | ||
import type { PackageJson } from 'type-fest'; | ||
export declare const GLINT_EXTENSIONS: string[]; | ||
export declare const GLINT_PROJECT_FILES: string[]; | ||
export declare const GLINT_PROJECT_DEPENDENCIES: string[]; | ||
export declare function isApp(packageJson: PackageJson): boolean; | ||
export declare function isAddon(packageJson: PackageJson): boolean; | ||
export declare function isGlintProject(basePath: string): Promise<boolean>; | ||
@@ -6,0 +9,0 @@ export declare function fileContainsHbsImport(fileText: string): boolean; |
@@ -9,3 +9,21 @@ import { readFile } from 'node:fs/promises'; | ||
// of these, we use glint. Otherwise, we use the regular Rehearsal service | ||
export const GLINT_PROJECT_FILES = ['ember-source', '@glimmer/component', '@glimmerx/component']; | ||
export const GLINT_PROJECT_DEPENDENCIES = [ | ||
'ember-source', | ||
'@glimmer/component', | ||
'@glimmerx/component', | ||
]; | ||
export function isApp(packageJson) { | ||
return hasDevDependency(packageJson, 'ember-source') && !isAddon(packageJson); | ||
} | ||
function hasDevDependency(packageJson, packageName) { | ||
return !!(packageJson?.devDependencies && packageName in packageJson.devDependencies) ?? false; | ||
} | ||
export function isAddon(packageJson) { | ||
return hasKeyword(packageJson, 'ember-addon'); | ||
} | ||
function hasKeyword(packageJson, keyword) { | ||
return !!(packageJson?.keywords && | ||
Array.isArray(packageJson.keywords) && | ||
packageJson.keywords.includes(keyword)); | ||
} | ||
export async function isGlintProject(basePath) { | ||
@@ -23,3 +41,3 @@ const pkgPath = resolve(basePath, 'package.json'); | ||
return deps.some((pkgName) => { | ||
return GLINT_PROJECT_FILES.includes(pkgName); | ||
return GLINT_PROJECT_DEPENDENCIES.includes(pkgName); | ||
}); | ||
@@ -26,0 +44,0 @@ } |
@@ -31,3 +31,3 @@ import { Reporter } from '@rehearsal/reporter'; | ||
options?: PluginOptions; | ||
filter?: (fileName: string) => boolean; | ||
filter?: (fileName: string) => Promise<boolean> | boolean; | ||
}[]; | ||
@@ -48,5 +48,5 @@ context: PluginsRunnerContext; | ||
queue<PluginType extends Plugin = Plugin, PluginOptionsType extends PluginOptions = PluginOptions>(plugin: PluginFactory<PluginType, PluginOptionsType>): this; | ||
queue<PluginType extends Plugin = Plugin, PluginOptionsType extends PluginOptions = PluginOptions>(plugin: PluginFactory<PluginType, PluginOptionsType>, filter: (fileName: string) => boolean): this; | ||
queue<PluginType extends Plugin = Plugin, PluginOptionsType extends PluginOptions = PluginOptions>(plugin: PluginFactory<PluginType, PluginOptionsType>, filter: (fileName: string) => Promise<boolean> | boolean): this; | ||
queue<PluginType extends Plugin = Plugin, PluginOptionsType extends PluginOptions = PluginOptions>(plugin: PluginFactory<PluginType, PluginOptionsType>, options: PluginOptionsType): this; | ||
queue<PluginType extends Plugin = Plugin, PluginOptionsType extends PluginOptions = PluginOptions>(plugin: PluginFactory<PluginType, PluginOptionsType>, options: PluginOptionsType, filter: (fileName: string) => boolean): this; | ||
queue<PluginType extends Plugin = Plugin, PluginOptionsType extends PluginOptions = PluginOptions>(plugin: PluginFactory<PluginType, PluginOptionsType>, options: PluginOptionsType, filter: (fileName: string) => Promise<boolean> | boolean): this; | ||
run(fileNames: string[], logger?: PluginLogger): AsyncGenerator<string>; | ||
@@ -53,0 +53,0 @@ processFilesGenerator(fileNames: string[], logger?: PluginLogger): AsyncGenerator<string>; |
@@ -75,3 +75,4 @@ export class Plugin { | ||
if (layer.filter) { | ||
if (!layer.filter(fileName)) { | ||
const filtered = await layer.filter(fileName); | ||
if (!filtered) { | ||
yield allChangedFiles; | ||
@@ -78,0 +79,0 @@ continue; |
@@ -19,2 +19,3 @@ import { ApplyCodeActionCommandResult, InstallPackageOptions, LanguageServiceHost } from 'typescript'; | ||
constructor(compilerOptions: CompilerOptions, fileNames: string[]); | ||
useCaseSensitiveFileNames: () => boolean; | ||
getTypeRootsVersion(): number; | ||
@@ -25,3 +26,2 @@ /** | ||
setScriptSnapshot(fileName: string, snapshot: IScriptSnapshot): IScriptSnapshot; | ||
installPackage(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>; | ||
/** | ||
@@ -33,2 +33,3 @@ * Gets the latest snapshot | ||
isKnownTypesPackageName(): boolean; | ||
installPackage(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>; | ||
getCompilationSettings: () => CompilerOptions; | ||
@@ -35,0 +36,0 @@ getCurrentDirectory: () => string; |
import { dirname } from 'node:path'; | ||
import { statSync } from 'fs'; | ||
import ts from 'typescript'; | ||
import { addDep } from '@rehearsal/utils'; | ||
import findupSync from 'findup-sync'; | ||
import { findUpSync } from 'find-up'; | ||
const { ScriptSnapshot, getDefaultLibFilePath, sys } = ts; | ||
@@ -19,2 +20,6 @@ /** | ||
this.typeRootVersion = 0; | ||
this.useCaseSensitiveFileNames = () => { | ||
return !(statSync(process.cwd().toLowerCase(), { throwIfNoEntry: false })?.isDirectory() && | ||
statSync(process.cwd().toUpperCase(), { throwIfNoEntry: false })?.isDirectory()); | ||
}; | ||
this.getCompilationSettings = () => this.compilerOptions; | ||
@@ -25,16 +30,9 @@ this.getCurrentDirectory = () => this.currentDirectory; | ||
this.getScriptVersion = (fileName) => this.files[fileName]?.version.toString() || '0'; | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
this.fileExists = sys.fileExists; | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
this.readFile = sys.readFile; | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
this.writeFile = sys.writeFile; | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
this.directoryExists = sys.directoryExists; | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
this.getDirectories = sys.getDirectories; | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
this.readDirectory = sys.readDirectory; | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
this.realpath = sys.realpath; | ||
this.fileExists = sys.fileExists.bind(this); | ||
this.readFile = sys.readFile.bind(this); | ||
this.writeFile = sys.writeFile.bind(this); | ||
this.directoryExists = sys.directoryExists.bind(this); | ||
this.getDirectories = sys.getDirectories.bind(this); | ||
this.readDirectory = sys.readDirectory.bind(this); | ||
this.realpath = sys.realpath?.bind(this); | ||
this.compilerOptions = compilerOptions; | ||
@@ -57,2 +55,19 @@ this.currentDirectory = process.cwd(); | ||
} | ||
/** | ||
* Gets the latest snapshot | ||
* If a snapshot doesn't exist yet - reads its content from file as the first version | ||
*/ | ||
getScriptSnapshot(fileName) { | ||
if (!(fileName in this.files) && this.fileExists(fileName)) { | ||
const text = this.readFile(fileName); | ||
if (text !== undefined) { | ||
this.setScriptSnapshot(fileName, ScriptSnapshot.fromString(text)); | ||
} | ||
} | ||
return this.files[fileName].snapshot; | ||
} | ||
isKnownTypesPackageName() { | ||
// Try all packages that come through here | ||
return true; | ||
} | ||
async installPackage(options) { | ||
@@ -64,3 +79,3 @@ if (this.seenTypingsRequest.has(options.fileName)) { | ||
this.seenTypingsRequest.set(options.fileName, options.packageName); | ||
const nearestPackageJSON = findupSync('package.json', { | ||
const nearestPackageJSON = findUpSync('package.json', { | ||
cwd: dirname(options.fileName), | ||
@@ -80,20 +95,3 @@ }); | ||
} | ||
/** | ||
* Gets the latest snapshot | ||
* If a snapshot doesn't exist yet - reads its content from file as the first version | ||
*/ | ||
getScriptSnapshot(fileName) { | ||
if (!(fileName in this.files) && this.fileExists(fileName)) { | ||
const text = this.readFile(fileName); | ||
if (text !== undefined) { | ||
this.setScriptSnapshot(fileName, ScriptSnapshot.fromString(text)); | ||
} | ||
} | ||
return this.files[fileName].snapshot; | ||
} | ||
isKnownTypesPackageName() { | ||
// try all packages that come through here | ||
return true; | ||
} | ||
} | ||
//# sourceMappingURL=rehearsal-service-host.js.map |
@@ -80,3 +80,4 @@ import ts from 'typescript'; | ||
code: 7050, | ||
messageText: `${node.name.getText()} don't have a return type, but the type may be inferred from usage.`, | ||
messageText: (isFunctionDeclaration(node) ? `Function` : `Method`) + | ||
` '${node.name.getText()}' lacks a return-type annotation.`, | ||
}); | ||
@@ -83,0 +84,0 @@ return undefined; |
{ | ||
"name": "@rehearsal/service", | ||
"version": "2.0.0-beta", | ||
"version": "2.0.0", | ||
"description": "Rehearsal Service", | ||
@@ -31,19 +31,19 @@ "keywords": [ | ||
"dependencies": { | ||
"findup-sync": "^5.0.0", | ||
"@glint/core": "^1.0.2", | ||
"find-up": "^6.3.0", | ||
"vscode-languageserver": "^8.1.0", | ||
"vscode-uri": "^3.0.7", | ||
"winston": "^3.8.2", | ||
"@rehearsal/reporter": "2.0.0-beta", | ||
"@rehearsal/utils": "2.0.0-beta" | ||
"@rehearsal/reporter": "2.0.0", | ||
"@rehearsal/utils": "2.0.0" | ||
}, | ||
"devDependencies": { | ||
"@vitest/coverage-c8": "^0.30.1", | ||
"@vitest/coverage-c8": "^0.33.0", | ||
"type-fest": "^3.8.0", | ||
"vitest": "^0.29.8" | ||
"vitest": "^0.30.0" | ||
}, | ||
"peerDependencies": { | ||
"@glint/core": "1.0.0-beta.4", | ||
"typescript": "^5.0" | ||
"typescript": "^5.1" | ||
}, | ||
"packageManager": "pnpm@8.2.0", | ||
"packageManager": "pnpm@8.6.7", | ||
"engines": { | ||
@@ -61,3 +61,2 @@ "node": ">=14.16.0" | ||
"test": "vitest --run --config ./vitest.config.ts --coverage", | ||
"test:slow": "vitest --run", | ||
"test:watch": "vitest --coverage --watch", | ||
@@ -64,0 +63,0 @@ "version": "pnpm version" |
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
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
Sorry, the diff of this file is not supported yet
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
722
1
192237
28
1
+ Added@glint/core@^1.0.2
+ Addedfind-up@^6.3.0
+ Added@glint/core@1.5.2(transitive)
+ Added@rehearsal/reporter@2.0.0(transitive)
+ Added@rehearsal/utils@2.0.0(transitive)
+ Addedfind-up@6.3.0(transitive)
+ Addedlocate-path@7.2.0(transitive)
+ Addedp-limit@4.0.0(transitive)
+ Addedp-locate@6.0.0(transitive)
+ Addedpath-exists@5.0.0(transitive)
+ Addedyocto-queue@1.1.1(transitive)
- Removedfindup-sync@^5.0.0
- Removed@glint/core@1.0.0-beta.4(transitive)
- Removed@rehearsal/reporter@2.0.0-beta(transitive)
- Removed@rehearsal/utils@2.0.0-beta(transitive)
- Removedargparse@2.0.1(transitive)
- Removedbalanced-match@1.0.2(transitive)
- Removedbrace-expansion@2.0.1(transitive)
- Removedbraces@3.0.3(transitive)
- Removedchalk@5.4.1(transitive)
- Removedcommander@10.0.1(transitive)
- Removedcompare-versions@6.0.0-rc.1(transitive)
- Removeddetect-file@1.0.0(transitive)
- Removedexpand-tilde@2.0.2(transitive)
- Removedfill-range@7.1.1(transitive)
- Removedfindup-sync@5.0.0(transitive)
- Removedfs.realpath@1.0.0(transitive)
- Removedglob@9.3.5(transitive)
- Removedglobal-modules@1.0.0(transitive)
- Removedglobal-prefix@1.0.2(transitive)
- Removedhomedir-polyfill@1.0.3(transitive)
- Removedini@1.3.8(transitive)
- Removedis-extglob@2.1.1(transitive)
- Removedis-glob@4.0.3(transitive)
- Removedis-number@7.0.0(transitive)
- Removedis-windows@1.0.2(transitive)
- Removedjs-yaml@4.1.0(transitive)
- Removedlru-cache@10.4.3(transitive)
- Removedmicromatch@4.0.8(transitive)
- Removedminimatch@8.0.4(transitive)
- Removedminipass@4.2.87.1.2(transitive)
- Removedparse-passwd@1.0.0(transitive)
- Removedpath-scurry@1.11.1(transitive)
- Removedpicomatch@2.3.1(transitive)
- Removedresolve-dir@1.0.1(transitive)
- Removedto-regex-range@5.0.1(transitive)
- Removedwhich@1.3.1(transitive)
Updated@rehearsal/reporter@2.0.0
Updated@rehearsal/utils@2.0.0