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

@lit-labs/analyzer

Package Overview
Dependencies
Maintainers
11
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lit-labs/analyzer - npm Package Compare versions

Comparing version

to
0.12.1

lib/javascript/mixins.d.ts

2

index.d.ts

@@ -7,5 +7,5 @@ /**

export { Analyzer } from './lib/analyzer.js';
export type { Package, Module, Reference, Type, Event, Declaration, VariableDeclaration, ClassDeclaration, ClassField, ClassMethod, Parameter, Return, LitElementDeclaration, CustomElementDeclaration, LitElementExport, PackageJson, ModuleWithLitElementDeclarations, DeprecatableDescribed, FunctionDeclaration, } from './lib/model.js';
export type { Package, Module, Reference, Type, Event, Declaration, VariableDeclaration, ClassDeclaration, ClassField, ClassMethod, Parameter, Return, LitElementDeclaration, MixinDeclaration, CustomElementDeclaration, LitElementExport, PackageJson, ModuleWithLitElementDeclarations, DeprecatableDescribed, FunctionDeclaration, } from './lib/model.js';
export type { AbsolutePath, PackagePath } from './lib/paths.js';
export { getImportsStringForReferences } from './lib/model.js';
//# sourceMappingURL=index.d.ts.map

@@ -32,3 +32,3 @@ /**

};
export declare const getCustomElementDeclaration: (node: CustomElementClassDeclaration, analyzer: AnalyzerInterface) => CustomElementDeclaration;
export declare const getCustomElementDeclaration: (node: CustomElementClassDeclaration, analyzer: AnalyzerInterface, isMixinClass?: boolean) => CustomElementDeclaration;
//# sourceMappingURL=custom-elements.d.ts.map

@@ -10,2 +10,3 @@ /**

import { parseNodeJSDocInfo, parseNamedTypedJSDocInfo, } from '../javascript/jsdoc.js';
import { getBaseTypes } from '../utils.js';
const _isCustomElementClassDeclaration = (t, analyzer) => {

@@ -26,3 +27,3 @@ const declarations = t.getSymbol()?.getDeclarations();

const type = checker.getTypeAtLocation(node);
const baseTypes = checker.getBaseTypes(type);
const baseTypes = getBaseTypes(type);
for (const t of baseTypes) {

@@ -115,3 +116,3 @@ if (_isCustomElementClassDeclaration(t, analyzer)) {

};
export const getCustomElementDeclaration = (node, analyzer) => {
export const getCustomElementDeclaration = (node, analyzer, isMixinClass) => {
return new CustomElementDeclaration({

@@ -122,3 +123,3 @@ tagname: getTagName(node, analyzer),

...getJSDocData(node, analyzer),
getHeritage: () => getHeritage(node, analyzer),
getHeritage: () => getHeritage(node, analyzer, isMixinClass),
...getClassMembers(node, analyzer),

@@ -125,0 +126,0 @@ });

@@ -22,3 +22,3 @@ /**

*/
export declare const getClassDeclaration: (declaration: ts.ClassLikeDeclaration, name: string, analyzer: AnalyzerInterface, docNode?: ts.Node) => ClassDeclaration;
export declare const getClassDeclaration: (declaration: ts.ClassLikeDeclaration, name: string, analyzer: AnalyzerInterface, docNode?: ts.Node, isMixinClass?: boolean) => ClassDeclaration;
/**

@@ -40,5 +40,5 @@ * Returns the `fields` and `methods` of a class.

*/
export declare const getHeritage: (declaration: ts.ClassLikeDeclarationBase, analyzer: AnalyzerInterface) => ClassHeritage;
export declare const getHeritageFromExpression: (expression: ts.Expression, analyzer: AnalyzerInterface) => ClassHeritage;
export declare const getSuperClass: (expression: ts.Expression, analyzer: AnalyzerInterface) => Reference | undefined;
export declare const getHeritage: (declaration: ts.ClassLikeDeclarationBase, analyzer: AnalyzerInterface, isMixinClass?: boolean) => ClassHeritage;
export declare const getHeritageFromExpression: (expression: ts.Expression, analyzer: AnalyzerInterface, isMixinClass?: boolean) => ClassHeritage;
export declare const getSuperClassAndMixins: (expression: ts.Expression, foundMixins: Reference[], analyzer: AnalyzerInterface) => Reference | undefined;
export declare const isConstructorFieldInitializer: (expression: ts.Expression, typescript: typeof ts) => expression is ConstructorFieldInitializer;

@@ -50,3 +50,4 @@ type ConstructorFieldInitializer = ts.AssignmentExpression<ts.EqualsToken> & {

};
export declare const maybeGetAppliedMixin: (expression: ts.Expression, identifier: ts.Identifier, analyzer: AnalyzerInterface) => ClassDeclaration | undefined;
export {};
//# sourceMappingURL=classes.d.ts.map

@@ -8,3 +8,3 @@ /**

import { createDiagnostic } from '../errors.js';
import { ClassDeclaration, ClassField, ClassMethod, } from '../model.js';
import { ClassDeclaration, ClassField, ClassMethod, MixinDeclaration, } from '../model.js';
import { isLitElementSubclass, getLitElementDeclaration, } from '../lit-element/lit-element.js';

@@ -25,8 +25,8 @@ import { getReferenceForIdentifier } from '../references.js';

*/
export const getClassDeclaration = (declaration, name, analyzer, docNode) => {
export const getClassDeclaration = (declaration, name, analyzer, docNode, isMixinClass) => {
if (isLitElementSubclass(declaration, analyzer)) {
return getLitElementDeclaration(declaration, analyzer);
return getLitElementDeclaration(declaration, analyzer, isMixinClass);
}
if (isCustomElementSubclass(declaration, analyzer)) {
return getCustomElementDeclaration(declaration, analyzer);
return getCustomElementDeclaration(declaration, analyzer, isMixinClass);
}

@@ -36,3 +36,3 @@ return new ClassDeclaration({

node: declaration,
getHeritage: () => getHeritage(declaration, analyzer),
getHeritage: () => getHeritage(declaration, analyzer, isMixinClass),
...parseNodeJSDocInfo(docNode ?? declaration, analyzer),

@@ -201,7 +201,7 @@ ...getClassMembers(declaration, analyzer),

*/
export const getHeritage = (declaration, analyzer) => {
export const getHeritage = (declaration, analyzer, isMixinClass) => {
const extendsClause = declaration.heritageClauses?.find((c) => c.token === analyzer.typescript.SyntaxKind.ExtendsKeyword);
if (extendsClause !== undefined) {
if (extendsClause.types.length === 1) {
return getHeritageFromExpression(extendsClause.types[0].expression, analyzer);
return getHeritageFromExpression(extendsClause.types[0].expression, analyzer, isMixinClass);
}

@@ -220,13 +220,11 @@ analyzer.addDiagnostic(createDiagnostic({

};
export const getHeritageFromExpression = (expression, analyzer) => {
// TODO(kschaaf): Support for extracting mixing applications from the heritage
// expression https://github.com/lit/lit/issues/2998
export const getHeritageFromExpression = (expression, analyzer, isMixinClass) => {
const mixins = [];
const superClass = getSuperClass(expression, analyzer);
const superClass = getSuperClassAndMixins(expression, mixins, analyzer);
return {
superClass,
superClass: isMixinClass ? undefined : superClass,
mixins,
};
};
export const getSuperClass = (expression, analyzer) => {
export const getSuperClassAndMixins = (expression, foundMixins, analyzer) => {
// TODO(kschaaf) Could add support for inline class expressions here as well

@@ -236,6 +234,46 @@ if (analyzer.typescript.isIdentifier(expression)) {

}
else if (analyzer.typescript.isCallExpression(expression) &&
analyzer.typescript.isIdentifier(expression.expression)) {
// FYI we purposely restrict to identifiers since we represent mixins
// as references. If we want to support complex expressions in future,
// we will need to rework that in the model.
const mixinRef = getReferenceForIdentifier(expression.expression, analyzer);
// We need to eagerly dereference a mixin ref to know what argument the
// super class is passed into
let mixin;
try {
mixin = mixinRef?.dereference(MixinDeclaration);
}
catch (_err) {
// It wasn't a MixinDeclaration for whatever reason
mixin = undefined;
}
// TODO (43081j): consider supporting external mixins properly at some point
// An external mixin is one which we discovered via analysis (e.g. CEM)
// but don't have a reference to in sources. In future, we should support
// those as it is likely we will pull most dependencies from manifest
// analysis rather than source.
// See issue #4492
if (mixinRef === undefined || mixin === undefined) {
analyzer.addDiagnostic(createDiagnostic({
typescript: analyzer.typescript,
node: expression,
message: `This is presumed to be a mixin but it could not be found ` +
`in the current project. Mixins imported from outside the ` +
`project are not yet supported ` +
`(see https://github.com/lit/lit/issues/4492).`,
code: DiagnosticCode.UNSUPPORTED,
category: analyzer.typescript.DiagnosticCategory.Warning,
}));
return undefined;
}
foundMixins.push(mixinRef);
const superArg = expression.arguments[mixin.superClassArgIndex];
const superClass = getSuperClassAndMixins(superArg, foundMixins, analyzer);
return superClass;
}
analyzer.addDiagnostic(createDiagnostic({
typescript: analyzer.typescript,
node: expression,
message: `Expected expression to be a concrete superclass. Mixins are not yet supported.`,
message: `Expected expression to be a concrete superclass or mixin.`,
code: DiagnosticCode.UNSUPPORTED,

@@ -252,2 +290,23 @@ category: analyzer.typescript.DiagnosticCategory.Warning,

};
export const maybeGetAppliedMixin = (expression, identifier, analyzer) => {
if (analyzer.typescript.isCallExpression(expression) &&
analyzer.typescript.isIdentifier(expression.expression)) {
const mixinRef = getReferenceForIdentifier(expression.expression, analyzer);
try {
mixinRef?.dereference(MixinDeclaration);
}
catch (_err) {
return undefined;
}
const heritage = getHeritageFromExpression(expression, analyzer);
if (heritage.superClass) {
return new ClassDeclaration({
name: identifier.text,
node: expression,
getHeritage: () => heritage,
});
}
}
return undefined;
};
//# sourceMappingURL=classes.js.map

@@ -19,2 +19,5 @@ /**

*
* If this is a mixin function, the return value will be a `MixinDeclaration`
* model instead.
*
* Note, the `docNode` may differ from the `declaration` in the case of a const

@@ -21,0 +24,0 @@ * assignment to a class expression, as the JSDoc will be attached to the

@@ -7,4 +7,5 @@ /**

import { createDiagnostic } from '../errors.js';
import { FunctionDeclaration, FunctionOverloadDeclaration, } from '../model.js';
import { FunctionDeclaration, FunctionOverloadDeclaration, MixinDeclaration, } from '../model.js';
import { getTypeForNode, getTypeForType } from '../types.js';
import { maybeGetMixinFromFunctionLike } from './mixins.js';
import { parseJSDocDescription, parseNodeJSDocInfo } from './jsdoc.js';

@@ -47,2 +48,5 @@ import { hasDefaultModifier, hasExportModifier } from '../utils.js';

*
* If this is a mixin function, the return value will be a `MixinDeclaration`
* model instead.
*
* Note, the `docNode` may differ from the `declaration` in the case of a const

@@ -53,2 +57,10 @@ * assignment to a class expression, as the JSDoc will be attached to the

export const getFunctionDeclaration = (declaration, name, analyzer, docNode) => {
const mixinDeclarationInfo = maybeGetMixinFromFunctionLike(declaration, name, analyzer);
if (mixinDeclarationInfo !== undefined) {
return new MixinDeclaration({
...mixinDeclarationInfo,
...parseNodeJSDocInfo(docNode ?? declaration, analyzer),
...getFunctionLikeInfo(declaration, name, analyzer),
});
}
return new FunctionDeclaration({

@@ -55,0 +67,0 @@ ...parseNodeJSDocInfo(docNode ?? declaration, analyzer),

@@ -11,3 +11,3 @@ /**

import { getFunctionDeclaration } from './functions.js';
import { getClassDeclaration } from './classes.js';
import { getClassDeclaration, maybeGetAppliedMixin } from './classes.js';
import { createDiagnostic } from '../errors.js';

@@ -36,2 +36,10 @@ import { DiagnosticCode } from '../diagnostic-code.js';

}
else {
// This supports const assignments of mixins applied to classes, ala:
// `export const MyClassWithSomeMixin = SomeMixin(MyClass);`
const classDec = maybeGetAppliedMixin(initializer, name, analyzer);
if (classDec !== undefined) {
return classDec;
}
}
}

@@ -38,0 +46,0 @@ return new VariableDeclaration({

@@ -18,3 +18,3 @@ /**

*/
export declare const getLitElementDeclaration: (declaration: LitClassDeclaration, analyzer: AnalyzerInterface) => LitElementDeclaration;
export declare const getLitElementDeclaration: (declaration: LitClassDeclaration, analyzer: AnalyzerInterface, isMixinClass?: boolean) => LitElementDeclaration;
/**

@@ -21,0 +21,0 @@ * This type identifies a ClassDeclaration as one that inherits from LitElement.

@@ -11,2 +11,3 @@ /**

import { getJSDocData, getTagName as getCustomElementTagName, } from '../custom-elements/custom-elements.js';
import { getBaseTypes } from '../utils.js';
/**

@@ -16,3 +17,3 @@ * Gets an analyzer LitElementDeclaration object from a ts.ClassDeclaration

*/
export const getLitElementDeclaration = (declaration, analyzer) => {
export const getLitElementDeclaration = (declaration, analyzer, isMixinClass) => {
return new LitElementDeclaration({

@@ -25,3 +26,3 @@ tagname: getTagName(declaration, analyzer),

...getJSDocData(declaration, analyzer),
getHeritage: () => getHeritage(declaration, analyzer),
getHeritage: () => getHeritage(declaration, analyzer, isMixinClass),
...getClassMembers(declaration, analyzer),

@@ -71,9 +72,9 @@ });

const type = checker.getTypeAtLocation(node);
const baseTypes = checker.getBaseTypes(type);
for (const t of baseTypes) {
if (_isLitElementClassDeclaration(t, analyzer)) {
return true;
}
}
return false;
const baseTypes = getBaseTypes(type);
return baseTypes.some((t) =>
// Mixins will cause the base types to be an intersection that
// includes `LitElement`
t.isIntersection()
? t.types.some((t) => _isLitElementClassDeclaration(t, analyzer))
: _isLitElementClassDeclaration(t, analyzer));
};

@@ -80,0 +81,0 @@ /**

@@ -179,2 +179,3 @@ /**

isFunctionDeclaration(): this is FunctionDeclaration;
isMixinDeclaration(): this is MixinDeclaration;
isClassField(): this is ClassField;

@@ -257,3 +258,3 @@ isClassMethod(): this is ClassMethod;

export interface ClassDeclarationInit extends DeclarationInit {
node: ts.ClassLikeDeclaration;
node: ts.ClassDeclaration | ts.ClassLikeDeclaration | ts.CallExpression;
getHeritage: () => ClassHeritage;

@@ -272,3 +273,3 @@ fieldMap?: Map<string, ClassField> | undefined;

readonly _staticMethodMap: Map<string, ClassMethod>;
readonly node: ts.ClassLikeDeclaration;
readonly node: ts.ClassLikeDeclaration | ts.CallExpression;
constructor(init: ClassDeclarationInit);

@@ -331,2 +332,11 @@ /**

}
export interface MixinDeclarationInit extends FunctionLikeInit {
classDeclaration: ClassDeclaration;
superClassArgIndex: number;
}
export declare class MixinDeclaration extends FunctionDeclaration {
readonly classDeclaration: ClassDeclaration;
readonly superClassArgIndex: number;
constructor(init: MixinDeclarationInit);
}
export interface Described {

@@ -333,0 +343,0 @@ description?: string | undefined;

@@ -168,2 +168,5 @@ /**

}
isMixinDeclaration() {
return this instanceof MixinDeclaration;
}
isClassField() {

@@ -307,2 +310,9 @@ return this instanceof ClassField;

}
export class MixinDeclaration extends FunctionDeclaration {
constructor(init) {
super(init);
this.classDeclaration = init.classDeclaration;
this.superClassArgIndex = init.superClassArgIndex;
}
}
export class CustomElementDeclaration extends ClassDeclaration {

@@ -309,0 +319,0 @@ constructor(init) {

@@ -21,2 +21,3 @@ /**

export declare const getPrivacy: (ts: TypeScript, node: ts.Node) => Privacy;
export declare const getBaseTypes: (type: ts.Type) => ts.BaseType[];
//# sourceMappingURL=utils.d.ts.map

@@ -42,2 +42,11 @@ /**

};
export const getBaseTypes = (type) => {
if (type.isClassOrInterface()) {
return type.getBaseTypes() ?? [];
}
if (type.isIntersection()) {
return type.types.map(getBaseTypes).flat();
}
return [];
};
//# sourceMappingURL=utils.js.map
{
"name": "@lit-labs/analyzer",
"version": "0.12.0",
"version": "0.12.1",
"publishConfig": {

@@ -5,0 +5,0 @@ "access": "public"

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

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