routie dev init since i didn't adhere to any proper guidance up until now
This commit is contained in:
+76
@@ -0,0 +1,76 @@
|
||||
const require_runtime = require('../../_virtual/_rolldown/runtime.js');
|
||||
const require_ts_types$1 = require('./ts-types.js');
|
||||
const require_ts_ast$1 = require('./ts-ast.js');
|
||||
|
||||
//#region lib/utils/ts-utils/index.js
|
||||
var require_ts_utils = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
|
||||
const { isTypeNode, extractRuntimeProps, isTSTypeLiteral, isTSTypeLiteralOrTSFunctionType, extractRuntimeEmits, flattenTypeNodes, isTSInterfaceBody, extractRuntimeSlots } = require_ts_ast$1.default;
|
||||
const { getComponentPropsFromTypeDefineTypes, getComponentEmitsFromTypeDefineTypes, getComponentSlotsFromTypeDefineTypes } = require_ts_types$1.default;
|
||||
/**
|
||||
* @typedef {import('@typescript-eslint/types').TSESTree.TypeNode} TSESTreeTypeNode
|
||||
*/
|
||||
/**
|
||||
* @typedef {import('../index').ComponentTypeProp} ComponentTypeProp
|
||||
* @typedef {import('../index').ComponentInferTypeProp} ComponentInferTypeProp
|
||||
* @typedef {import('../index').ComponentUnknownProp} ComponentUnknownProp
|
||||
* @typedef {import('../index').ComponentTypeEmit} ComponentTypeEmit
|
||||
* @typedef {import('../index').ComponentInferTypeEmit} ComponentInferTypeEmit
|
||||
* @typedef {import('../index').ComponentUnknownEmit} ComponentUnknownEmit
|
||||
* @typedef {import('../index').ComponentTypeSlot} ComponentTypeSlot
|
||||
* @typedef {import('../index').ComponentInferTypeSlot} ComponentInferTypeSlot
|
||||
* @typedef {import('../index').ComponentUnknownSlot} ComponentUnknownSlot
|
||||
*/
|
||||
module.exports = {
|
||||
isTypeNode,
|
||||
getComponentPropsFromTypeDefine,
|
||||
getComponentEmitsFromTypeDefine,
|
||||
getComponentSlotsFromTypeDefine
|
||||
};
|
||||
/**
|
||||
* Get all props by looking at all component's properties
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {TypeNode} propsNode Type with props definition
|
||||
* @return {(ComponentTypeProp|ComponentInferTypeProp|ComponentUnknownProp)[]} Array of component props
|
||||
*/
|
||||
function getComponentPropsFromTypeDefine(context, propsNode) {
|
||||
/** @type {(ComponentTypeProp|ComponentInferTypeProp|ComponentUnknownProp)[]} */
|
||||
const result = [];
|
||||
for (const defNode of flattenTypeNodes(context, propsNode)) if (isTSInterfaceBody(defNode) || isTSTypeLiteral(defNode)) result.push(...extractRuntimeProps(context, defNode));
|
||||
else result.push(...getComponentPropsFromTypeDefineTypes(context, defNode));
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Get all emits by looking at all component's properties
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {TypeNode} emitsNode Type with emits definition
|
||||
* @return {(ComponentTypeEmit|ComponentInferTypeEmit|ComponentUnknownEmit)[]} Array of component emits
|
||||
*/
|
||||
function getComponentEmitsFromTypeDefine(context, emitsNode) {
|
||||
/** @type {(ComponentTypeEmit|ComponentInferTypeEmit|ComponentUnknownEmit)[]} */
|
||||
const result = [];
|
||||
for (const defNode of flattenTypeNodes(context, emitsNode)) if (isTSInterfaceBody(defNode) || isTSTypeLiteralOrTSFunctionType(defNode)) result.push(...extractRuntimeEmits(defNode));
|
||||
else result.push(...getComponentEmitsFromTypeDefineTypes(context, defNode));
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Get all slots by looking at all component's properties
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {TypeNode} slotsNode Type with slots definition
|
||||
* @return {(ComponentTypeSlot|ComponentInferTypeSlot|ComponentUnknownSlot)[]} Array of component slots
|
||||
*/
|
||||
function getComponentSlotsFromTypeDefine(context, slotsNode) {
|
||||
/** @type {(ComponentTypeSlot|ComponentInferTypeSlot|ComponentUnknownSlot)[]} */
|
||||
const result = [];
|
||||
for (const defNode of flattenTypeNodes(context, slotsNode)) if (isTSInterfaceBody(defNode) || isTSTypeLiteral(defNode)) result.push(...extractRuntimeSlots(defNode));
|
||||
else result.push(...getComponentSlotsFromTypeDefineTypes(context, defNode));
|
||||
return result;
|
||||
}
|
||||
}));
|
||||
|
||||
//#endregion
|
||||
Object.defineProperty(exports, 'default', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return require_ts_utils();
|
||||
}
|
||||
});
|
||||
+385
@@ -0,0 +1,385 @@
|
||||
const require_runtime = require('../../_virtual/_rolldown/runtime.js');
|
||||
const require_scope$1 = require('../scope.js');
|
||||
const require_ts_types$1 = require('./ts-types.js');
|
||||
|
||||
//#region lib/utils/ts-utils/ts-ast.js
|
||||
var require_ts_ast = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
|
||||
const { getScope } = require_scope$1.default;
|
||||
const { findVariable } = require("@eslint-community/eslint-utils");
|
||||
const { inferRuntimeTypeFromTypeNode } = require_ts_types$1.default;
|
||||
/**
|
||||
* @typedef {import('@typescript-eslint/types').TSESTree.TypeNode} TSESTreeTypeNode
|
||||
* @typedef {import('@typescript-eslint/types').TSESTree.TSInterfaceBody} TSESTreeTSInterfaceBody
|
||||
* @typedef {import('@typescript-eslint/types').TSESTree.TSTypeLiteral} TSESTreeTSTypeLiteral
|
||||
* @typedef {import('@typescript-eslint/types').TSESTree.TSFunctionType} TSESTreeTSFunctionType
|
||||
* @typedef {import('@typescript-eslint/types').TSESTree.Parameter} TSESTreeParameter
|
||||
* @typedef {import('@typescript-eslint/types').TSESTree.Node} TSESTreeNode
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @typedef {import('../index').ComponentTypeProp} ComponentTypeProp
|
||||
* @typedef {import('../index').ComponentUnknownProp} ComponentUnknownProp
|
||||
* @typedef {import('../index').ComponentTypeEmit} ComponentTypeEmit
|
||||
* @typedef {import('../index').ComponentUnknownEmit} ComponentUnknownEmit
|
||||
* @typedef {import('../index').ComponentTypeSlot} ComponentTypeSlot
|
||||
* @typedef {import('../index').ComponentUnknownSlot} ComponentUnknownSlot
|
||||
*/
|
||||
const noop = Function.prototype;
|
||||
module.exports = {
|
||||
isTypeNode,
|
||||
flattenTypeNodes,
|
||||
isTSInterfaceBody,
|
||||
isTSTypeLiteral,
|
||||
isTSTypeLiteralOrTSFunctionType,
|
||||
extractRuntimeProps,
|
||||
extractRuntimeEmits,
|
||||
extractRuntimeSlots
|
||||
};
|
||||
/**
|
||||
* @param {ASTNode} node
|
||||
* @returns {node is TypeNode}
|
||||
*/
|
||||
function isTypeNode(node) {
|
||||
if (node.type === "TSAbstractKeyword" || node.type === "TSAnyKeyword" || node.type === "TSAsyncKeyword" || node.type === "TSArrayType" || node.type === "TSBigIntKeyword" || node.type === "TSBooleanKeyword" || node.type === "TSConditionalType" || node.type === "TSConstructorType" || node.type === "TSDeclareKeyword" || node.type === "TSExportKeyword" || node.type === "TSFunctionType" || node.type === "TSImportType" || node.type === "TSIndexedAccessType" || node.type === "TSInferType" || node.type === "TSIntersectionType" || node.type === "TSIntrinsicKeyword" || node.type === "TSLiteralType" || node.type === "TSMappedType" || node.type === "TSNamedTupleMember" || node.type === "TSNeverKeyword" || node.type === "TSNullKeyword" || node.type === "TSNumberKeyword" || node.type === "TSObjectKeyword" || node.type === "TSOptionalType" || node.type === "TSQualifiedName" || node.type === "TSPrivateKeyword" || node.type === "TSProtectedKeyword" || node.type === "TSPublicKeyword" || node.type === "TSReadonlyKeyword" || node.type === "TSRestType" || node.type === "TSStaticKeyword" || node.type === "TSStringKeyword" || node.type === "TSSymbolKeyword" || node.type === "TSTemplateLiteralType" || node.type === "TSThisType" || node.type === "TSTupleType" || node.type === "TSTypeLiteral" || node.type === "TSTypeOperator" || node.type === "TSTypePredicate" || node.type === "TSTypeQuery" || node.type === "TSTypeReference" || node.type === "TSUndefinedKeyword" || node.type === "TSUnionType" || node.type === "TSUnknownKeyword" || node.type === "TSVoidKeyword") {
|
||||
/** @type {TypeNode['type']} for type check */
|
||||
const type = node.type;
|
||||
noop(type);
|
||||
return true;
|
||||
}
|
||||
/** @type {Exclude<ASTNode['type'], TypeNode['type']>} for type check */
|
||||
const type = node.type;
|
||||
noop(type);
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @param {TSESTreeTypeNode|TSESTreeTSInterfaceBody} node
|
||||
* @returns {node is TSESTreeTSInterfaceBody}
|
||||
*/
|
||||
function isTSInterfaceBody(node) {
|
||||
return node.type === "TSInterfaceBody";
|
||||
}
|
||||
/**
|
||||
* @param {TSESTreeTypeNode} node
|
||||
* @returns {node is TSESTreeTSTypeLiteral}
|
||||
*/
|
||||
function isTSTypeLiteral(node) {
|
||||
return node.type === "TSTypeLiteral";
|
||||
}
|
||||
/**
|
||||
* @param {TSESTreeTypeNode} node
|
||||
* @returns {node is TSESTreeTSFunctionType}
|
||||
*/
|
||||
function isTSFunctionType(node) {
|
||||
return node.type === "TSFunctionType";
|
||||
}
|
||||
/**
|
||||
* @param {TSESTreeTypeNode} node
|
||||
* @returns {node is TSESTreeTSTypeLiteral | TSESTreeTSFunctionType}
|
||||
*/
|
||||
function isTSTypeLiteralOrTSFunctionType(node) {
|
||||
return isTSTypeLiteral(node) || isTSFunctionType(node);
|
||||
}
|
||||
/**
|
||||
* @see https://github.com/vuejs/vue-next/blob/253ca2729d808fc051215876aa4af986e4caa43c/packages/compiler-sfc/src/compileScript.ts#L1512
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {TSESTreeTSTypeLiteral | TSESTreeTSInterfaceBody} node
|
||||
* @returns {IterableIterator<ComponentTypeProp | ComponentUnknownProp>}
|
||||
*/
|
||||
function* extractRuntimeProps(context, node) {
|
||||
const members = node.type === "TSTypeLiteral" ? node.members : node.body;
|
||||
for (const member of members) if (member.type === "TSPropertySignature" || member.type === "TSMethodSignature") {
|
||||
if (member.key.type !== "Identifier" && member.key.type !== "Literal") {
|
||||
yield {
|
||||
type: "unknown",
|
||||
propName: null,
|
||||
node: member.key
|
||||
};
|
||||
continue;
|
||||
}
|
||||
/** @type {string[]|undefined} */
|
||||
let types;
|
||||
if (member.type === "TSMethodSignature") types = ["Function"];
|
||||
else if (member.typeAnnotation) types = inferRuntimeType(context, member.typeAnnotation.typeAnnotation);
|
||||
yield {
|
||||
type: "type",
|
||||
key: member.key,
|
||||
propName: member.key.type === "Identifier" ? member.key.name : `${member.key.value}`,
|
||||
node: member,
|
||||
required: !member.optional,
|
||||
types: types || [`null`]
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {TSESTreeTSTypeLiteral | TSESTreeTSInterfaceBody | TSESTreeTSFunctionType} node
|
||||
* @returns {IterableIterator<ComponentTypeEmit | ComponentUnknownEmit>}
|
||||
*/
|
||||
function* extractRuntimeEmits(node) {
|
||||
if (node.type === "TSFunctionType") {
|
||||
yield* extractEventNames(node.params[0], node);
|
||||
return;
|
||||
}
|
||||
const members = node.type === "TSTypeLiteral" ? node.members : node.body;
|
||||
for (const member of members) if (member.type === "TSCallSignatureDeclaration") yield* extractEventNames(member.params[0], member);
|
||||
else if (member.type === "TSPropertySignature" || member.type === "TSMethodSignature") {
|
||||
if (member.key.type !== "Identifier" && member.key.type !== "Literal") {
|
||||
yield {
|
||||
type: "unknown",
|
||||
emitName: null,
|
||||
node: member.key
|
||||
};
|
||||
continue;
|
||||
}
|
||||
yield {
|
||||
type: "type",
|
||||
key: member.key,
|
||||
emitName: member.key.type === "Identifier" ? member.key.name : `${member.key.value}`,
|
||||
node: member
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {TSESTreeTSTypeLiteral | TSESTreeTSInterfaceBody} node
|
||||
* @returns {IterableIterator<ComponentTypeSlot | ComponentUnknownSlot>}
|
||||
*/
|
||||
function* extractRuntimeSlots(node) {
|
||||
const members = node.type === "TSTypeLiteral" ? node.members : node.body;
|
||||
for (const member of members) if (member.type === "TSPropertySignature" || member.type === "TSMethodSignature") {
|
||||
if (member.key.type !== "Identifier" && member.key.type !== "Literal") {
|
||||
yield {
|
||||
type: "unknown",
|
||||
slotName: null,
|
||||
node: member.key
|
||||
};
|
||||
continue;
|
||||
}
|
||||
yield {
|
||||
type: "type",
|
||||
key: member.key,
|
||||
slotName: member.key.type === "Identifier" ? member.key.name : `${member.key.value}`,
|
||||
node: member
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {TSESTreeParameter} eventName
|
||||
* @param {TSCallSignatureDeclaration | TSFunctionType} member
|
||||
* @returns {IterableIterator<ComponentTypeEmit>}
|
||||
*/
|
||||
function* extractEventNames(eventName, member) {
|
||||
if (eventName && eventName.type === "Identifier" && eventName.typeAnnotation && eventName.typeAnnotation.type === "TSTypeAnnotation") {
|
||||
const typeNode = eventName.typeAnnotation.typeAnnotation;
|
||||
if (typeNode.type === "TSLiteralType" && typeNode.literal.type === "Literal") yield {
|
||||
type: "type",
|
||||
key: typeNode,
|
||||
emitName: String(typeNode.literal.value),
|
||||
node: member
|
||||
};
|
||||
else if (typeNode.type === "TSUnionType") {
|
||||
for (const t of typeNode.types) if (t.type === "TSLiteralType" && t.literal.type === "Literal") yield {
|
||||
type: "type",
|
||||
key: t,
|
||||
emitName: String(t.literal.value),
|
||||
node: member
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {TSESTreeTypeNode} node
|
||||
* @returns {(TSESTreeTypeNode|TSESTreeTSInterfaceBody)[]}
|
||||
*/
|
||||
function flattenTypeNodes(context, node) {
|
||||
/**
|
||||
* @typedef {object} TraversedData
|
||||
* @property {Set<TSESTreeTypeNode|TSESTreeTSInterfaceBody>} nodes
|
||||
* @property {boolean} finished
|
||||
*/
|
||||
/** @type {Map<TSESTreeTypeNode,TraversedData>} */
|
||||
const traversed = /* @__PURE__ */ new Map();
|
||||
return [...flattenImpl(node)];
|
||||
/**
|
||||
* @param {TSESTreeTypeNode} node
|
||||
* @returns {Iterable<TSESTreeTypeNode|TSESTreeTSInterfaceBody>}
|
||||
*/
|
||||
function* flattenImpl(node) {
|
||||
if (node.type === "TSUnionType" || node.type === "TSIntersectionType") {
|
||||
for (const typeNode of node.types) yield* flattenImpl(typeNode);
|
||||
return;
|
||||
}
|
||||
if (node.type === "TSTypeReference" && node.typeName.type === "Identifier") {
|
||||
const refName = node.typeName.name;
|
||||
const variable = findVariable(getScope(context, node), refName);
|
||||
if (variable && variable.defs.length === 1) {
|
||||
const defNode = variable.defs[0].node;
|
||||
if (defNode.type === "TSInterfaceDeclaration") {
|
||||
yield defNode.body;
|
||||
return;
|
||||
} else if (defNode.type === "TSTypeAliasDeclaration") {
|
||||
const typeAnnotation = defNode.typeAnnotation;
|
||||
let traversedData = traversed.get(typeAnnotation);
|
||||
if (traversedData) {
|
||||
yield* [...traversedData.nodes];
|
||||
if (!traversedData.finished) yield typeAnnotation;
|
||||
return;
|
||||
}
|
||||
traversedData = {
|
||||
nodes: /* @__PURE__ */ new Set(),
|
||||
finished: false
|
||||
};
|
||||
traversed.set(typeAnnotation, traversedData);
|
||||
for (const e of flattenImpl(typeAnnotation)) traversedData.nodes.add(e);
|
||||
traversedData.finished = true;
|
||||
yield* traversedData.nodes;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
yield node;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {TSESTreeTypeNode} node
|
||||
* @param {Set<TSESTreeTypeNode>} [checked]
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function inferRuntimeType(context, node, checked = /* @__PURE__ */ new Set()) {
|
||||
switch (node.type) {
|
||||
case "TSStringKeyword":
|
||||
case "TSTemplateLiteralType": return ["String"];
|
||||
case "TSNumberKeyword": return ["Number"];
|
||||
case "TSBooleanKeyword": return ["Boolean"];
|
||||
case "TSObjectKeyword": return ["Object"];
|
||||
case "TSTypeLiteral": return inferTypeLiteralType(node);
|
||||
case "TSFunctionType": return ["Function"];
|
||||
case "TSArrayType":
|
||||
case "TSTupleType": return ["Array"];
|
||||
case "TSSymbolKeyword": return ["Symbol"];
|
||||
case "TSLiteralType":
|
||||
if (node.literal.type === "Literal") switch (typeof node.literal.value) {
|
||||
case "boolean": return ["Boolean"];
|
||||
case "string": return ["String"];
|
||||
case "number":
|
||||
case "bigint": return ["Number"];
|
||||
}
|
||||
return inferRuntimeTypeFromTypeNode(context, node);
|
||||
case "TSTypeReference":
|
||||
if (node.typeName.type === "Identifier") {
|
||||
const variable = findVariable(getScope(context, node), node.typeName.name);
|
||||
if (variable && variable.defs.length === 1) {
|
||||
const defNode = variable.defs[0].node;
|
||||
if (defNode.type === "TSInterfaceDeclaration") return [`Object`];
|
||||
if (defNode.type === "TSTypeAliasDeclaration") {
|
||||
const typeAnnotation = defNode.typeAnnotation;
|
||||
if (!checked.has(typeAnnotation)) {
|
||||
checked.add(typeAnnotation);
|
||||
return inferRuntimeType(context, typeAnnotation, checked);
|
||||
}
|
||||
}
|
||||
if (defNode.type === "TSEnumDeclaration") return inferEnumType(context, defNode);
|
||||
}
|
||||
for (const name of [node.typeName.name, ...node.typeName.name.startsWith("Readonly") ? [node.typeName.name.slice(8)] : []]) switch (name) {
|
||||
case "Array":
|
||||
case "Function":
|
||||
case "Object":
|
||||
case "Set":
|
||||
case "Map":
|
||||
case "WeakSet":
|
||||
case "WeakMap":
|
||||
case "Date": return [name];
|
||||
}
|
||||
switch (node.typeName.name) {
|
||||
case "Record":
|
||||
case "Partial":
|
||||
case "Readonly":
|
||||
case "Pick":
|
||||
case "Omit":
|
||||
case "Required":
|
||||
case "InstanceType": return ["Object"];
|
||||
case "Uppercase":
|
||||
case "Lowercase":
|
||||
case "Capitalize":
|
||||
case "Uncapitalize": return ["String"];
|
||||
case "Parameters":
|
||||
case "ConstructorParameters": return ["Array"];
|
||||
case "NonNullable": {
|
||||
const typeArguments = "typeArguments" in node ? node.typeArguments : node.typeParameters;
|
||||
if (typeArguments && typeArguments.params[0]) return inferRuntimeType(context, typeArguments.params[0], checked).filter((t) => t !== "null");
|
||||
break;
|
||||
}
|
||||
case "Extract": {
|
||||
const typeArguments = "typeArguments" in node ? node.typeArguments : node.typeParameters;
|
||||
if (typeArguments && typeArguments.params[1]) return inferRuntimeType(context, typeArguments.params[1], checked);
|
||||
break;
|
||||
}
|
||||
case "Exclude":
|
||||
case "OmitThisParameter": {
|
||||
const typeArguments = "typeArguments" in node ? node.typeArguments : node.typeParameters;
|
||||
if (typeArguments && typeArguments.params[0]) return inferRuntimeType(context, typeArguments.params[0], checked);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return inferRuntimeTypeFromTypeNode(context, node);
|
||||
case "TSUnionType":
|
||||
case "TSIntersectionType": return inferUnionType(node);
|
||||
default: return inferRuntimeTypeFromTypeNode(context, node);
|
||||
}
|
||||
/**
|
||||
* @param {import('@typescript-eslint/types').TSESTree.TSUnionType|import('@typescript-eslint/types').TSESTree.TSIntersectionType} node
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function inferUnionType(node) {
|
||||
const types = /* @__PURE__ */ new Set();
|
||||
for (const t of node.types) for (const tt of inferRuntimeType(context, t, checked)) types.add(tt);
|
||||
return [...types];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {import('@typescript-eslint/types').TSESTree.TSTypeLiteral} node
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function inferTypeLiteralType(node) {
|
||||
const types = /* @__PURE__ */ new Set();
|
||||
for (const m of node.members) switch (m.type) {
|
||||
case "TSCallSignatureDeclaration":
|
||||
case "TSConstructSignatureDeclaration":
|
||||
types.add("Function");
|
||||
break;
|
||||
default: types.add("Object");
|
||||
}
|
||||
return types.size > 0 ? [...types] : ["Object"];
|
||||
}
|
||||
/**
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {import('@typescript-eslint/types').TSESTree.TSEnumDeclaration} node
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function inferEnumType(context, node) {
|
||||
const types = /* @__PURE__ */ new Set();
|
||||
for (const m of node.members) if (m.initializer) if (m.initializer.type === "Literal") switch (typeof m.initializer.value) {
|
||||
case "string":
|
||||
types.add("String");
|
||||
break;
|
||||
case "number":
|
||||
case "bigint":
|
||||
types.add("Number");
|
||||
break;
|
||||
case "boolean":
|
||||
types.add("Boolean");
|
||||
break;
|
||||
}
|
||||
else for (const type of inferRuntimeTypeFromTypeNode(context, m.initializer)) types.add(type);
|
||||
return types.size > 0 ? [...types] : ["Number"];
|
||||
}
|
||||
}));
|
||||
|
||||
//#endregion
|
||||
Object.defineProperty(exports, 'default', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return require_ts_ast();
|
||||
}
|
||||
});
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
const require_runtime = require('../../_virtual/_rolldown/runtime.js');
|
||||
const require_typescript$1 = require('./typescript.js');
|
||||
|
||||
//#region lib/utils/ts-utils/ts-types.js
|
||||
var require_ts_types = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
|
||||
const { getTypeScript, isAny, isUnknown, isNever, isNull, isObject, isFunction, isStringLike, isNumberLike, isBooleanLike, isBigIntLike, isArrayLikeObject, isReferenceObject } = require_typescript$1.default;
|
||||
/**
|
||||
* @typedef {import('@typescript-eslint/types').TSESTree.Node} TSESTreeNode
|
||||
* @typedef {import('typescript').Type} Type
|
||||
* @typedef {import('typescript').TypeChecker} TypeChecker
|
||||
* @typedef {import('typescript').Node} TypeScriptNode
|
||||
*/
|
||||
/**
|
||||
* @typedef {import('../index').ComponentInferTypeProp} ComponentInferTypeProp
|
||||
* @typedef {import('../index').ComponentUnknownProp} ComponentUnknownProp
|
||||
* @typedef {import('../index').ComponentInferTypeEmit} ComponentInferTypeEmit
|
||||
* @typedef {import('../index').ComponentUnknownEmit} ComponentUnknownEmit
|
||||
* @typedef {import('../index').ComponentInferTypeSlot} ComponentInferTypeSlot
|
||||
* @typedef {import('../index').ComponentUnknownSlot} ComponentUnknownSlot
|
||||
*/
|
||||
module.exports = {
|
||||
getComponentPropsFromTypeDefineTypes,
|
||||
getComponentEmitsFromTypeDefineTypes,
|
||||
getComponentSlotsFromTypeDefineTypes,
|
||||
inferRuntimeTypeFromTypeNode
|
||||
};
|
||||
/**
|
||||
* @typedef {object} Services
|
||||
* @property {typeof import("typescript")} ts
|
||||
* @property {Map<ESNode | TSNode | TSESTreeNode, TypeScriptNode>} tsNodeMap
|
||||
* @property {import('typescript').TypeChecker} checker
|
||||
*/
|
||||
/**
|
||||
* Get TypeScript parser services.
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @returns {Services|null}
|
||||
*/
|
||||
function getTSParserServices(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
const tsNodeMap = sourceCode.parserServices.esTreeNodeToTSNodeMap;
|
||||
if (!tsNodeMap) return null;
|
||||
const checker = sourceCode.parserServices.hasFullTypeInformation !== false && sourceCode.parserServices.program && sourceCode.parserServices.program.getTypeChecker() || null;
|
||||
if (!checker) return null;
|
||||
const ts = getTypeScript();
|
||||
if (!ts) return null;
|
||||
return {
|
||||
ts,
|
||||
tsNodeMap,
|
||||
checker
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Get all props by looking at all component's properties
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {TypeNode} propsNode Type with props definition
|
||||
* @return {(ComponentInferTypeProp|ComponentUnknownProp)[]} Array of component props
|
||||
*/
|
||||
function getComponentPropsFromTypeDefineTypes(context, propsNode) {
|
||||
const services = getTSParserServices(context);
|
||||
const tsNode = services && services.tsNodeMap.get(propsNode);
|
||||
const type = tsNode && services.checker.getTypeAtLocation(tsNode);
|
||||
if (!type || isAny(type) || isUnknown(type) || isNever(type) || isNull(type)) return [{
|
||||
type: "unknown",
|
||||
propName: null,
|
||||
node: propsNode
|
||||
}];
|
||||
return [...extractRuntimeProps(type, tsNode, propsNode, services)];
|
||||
}
|
||||
/**
|
||||
* Get all emits by looking at all component's properties
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {TypeNode} emitsNode Type with emits definition
|
||||
* @return {(ComponentInferTypeEmit|ComponentUnknownEmit)[]} Array of component emits
|
||||
*/
|
||||
function getComponentEmitsFromTypeDefineTypes(context, emitsNode) {
|
||||
const services = getTSParserServices(context);
|
||||
const tsNode = services && services.tsNodeMap.get(emitsNode);
|
||||
const type = tsNode && services.checker.getTypeAtLocation(tsNode);
|
||||
if (!type || isAny(type) || isUnknown(type) || isNever(type) || isNull(type)) return [{
|
||||
type: "unknown",
|
||||
emitName: null,
|
||||
node: emitsNode
|
||||
}];
|
||||
return [...extractRuntimeEmits(type, tsNode, emitsNode, services)];
|
||||
}
|
||||
/**
|
||||
* Get all slots by looking at all component's properties
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {TypeNode} slotsNode Type with slots definition
|
||||
* @return {(ComponentInferTypeSlot|ComponentUnknownSlot)[]} Array of component slots
|
||||
*/
|
||||
function getComponentSlotsFromTypeDefineTypes(context, slotsNode) {
|
||||
const services = getTSParserServices(context);
|
||||
const tsNode = services && services.tsNodeMap.get(slotsNode);
|
||||
const type = tsNode && services.checker.getTypeAtLocation(tsNode);
|
||||
if (!type || isAny(type) || isUnknown(type) || isNever(type) || isNull(type)) return [{
|
||||
type: "unknown",
|
||||
slotName: null,
|
||||
node: slotsNode
|
||||
}];
|
||||
return [...extractRuntimeSlots(type, slotsNode)];
|
||||
}
|
||||
/**
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {TypeNode|Expression} node
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function inferRuntimeTypeFromTypeNode(context, node) {
|
||||
const services = getTSParserServices(context);
|
||||
const tsNode = services && services.tsNodeMap.get(node);
|
||||
const type = tsNode && services.checker.getTypeAtLocation(tsNode);
|
||||
if (!type) return ["null"];
|
||||
return inferRuntimeTypeInternal(type, services);
|
||||
}
|
||||
/**
|
||||
* @param {Type} type
|
||||
* @param {TypeScriptNode} tsNode
|
||||
* @param {TypeNode} propsNode Type with props definition
|
||||
* @param {Services} services
|
||||
* @returns {IterableIterator<ComponentInferTypeProp>}
|
||||
*/
|
||||
function* extractRuntimeProps(type, tsNode, propsNode, services) {
|
||||
const { ts, checker } = services;
|
||||
for (const property of type.getProperties()) {
|
||||
const isOptional = (property.flags & ts.SymbolFlags.Optional) !== 0;
|
||||
const name = property.getName();
|
||||
const type = checker.getTypeOfSymbolAtLocation(property, tsNode);
|
||||
yield {
|
||||
type: "infer-type",
|
||||
propName: name,
|
||||
required: !isOptional,
|
||||
node: propsNode,
|
||||
types: inferRuntimeTypeInternal(type, services)
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {Type} type
|
||||
* @param {Services} services
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function inferRuntimeTypeInternal(type, services) {
|
||||
const { checker } = services;
|
||||
/** @type {Set<string>} */
|
||||
const types = /* @__PURE__ */ new Set();
|
||||
if (type.isTypeParameter()) {
|
||||
const constraint = type.getConstraint();
|
||||
if (constraint) for (const t of inferRuntimeTypeInternal(constraint, services)) types.add(t);
|
||||
return [...types];
|
||||
}
|
||||
for (const targetType of iterateTypes(checker.getNonNullableType(type))) if (isAny(targetType) || isUnknown(targetType) || isNever(targetType) || isNull(targetType)) types.add("null");
|
||||
else if (isStringLike(targetType)) types.add("String");
|
||||
else if (isNumberLike(targetType) || isBigIntLike(targetType)) types.add("Number");
|
||||
else if (isBooleanLike(targetType)) types.add("Boolean");
|
||||
else if (isFunction(targetType)) types.add("Function");
|
||||
else if (isArrayLikeObject(targetType) || targetType.isClassOrInterface() && ["Array", "ReadonlyArray"].includes(checker.getFullyQualifiedName(targetType.symbol))) types.add("Array");
|
||||
else if (isObject(targetType)) types.add("Object");
|
||||
if (types.size <= 0) types.add("null");
|
||||
return [...types];
|
||||
}
|
||||
/**
|
||||
* @param {Type} type
|
||||
* @param {TypeScriptNode} tsNode
|
||||
* @param {TypeNode} emitsNode Type with emits definition
|
||||
* @param {Services} services
|
||||
* @returns {IterableIterator<ComponentInferTypeEmit|ComponentUnknownEmit>}
|
||||
*/
|
||||
function* extractRuntimeEmits(type, tsNode, emitsNode, services) {
|
||||
const { checker } = services;
|
||||
if (isFunction(type)) for (const signature of type.getCallSignatures()) {
|
||||
const param = signature.getParameters()[0];
|
||||
if (!param) {
|
||||
yield {
|
||||
type: "unknown",
|
||||
emitName: null,
|
||||
node: emitsNode
|
||||
};
|
||||
continue;
|
||||
}
|
||||
const type = checker.getTypeOfSymbolAtLocation(param, tsNode);
|
||||
for (const targetType of iterateTypes(type)) yield targetType.isStringLiteral() ? {
|
||||
type: "infer-type",
|
||||
emitName: targetType.value,
|
||||
node: emitsNode
|
||||
} : {
|
||||
type: "unknown",
|
||||
emitName: null,
|
||||
node: emitsNode
|
||||
};
|
||||
}
|
||||
else if (isObject(type)) for (const property of type.getProperties()) yield {
|
||||
type: "infer-type",
|
||||
emitName: property.getName(),
|
||||
node: emitsNode
|
||||
};
|
||||
else yield {
|
||||
type: "unknown",
|
||||
emitName: null,
|
||||
node: emitsNode
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @param {Type} type
|
||||
* @param {TypeNode} slotsNode Type with slots definition
|
||||
* @returns {IterableIterator<ComponentInferTypeSlot>}
|
||||
*/
|
||||
function* extractRuntimeSlots(type, slotsNode) {
|
||||
for (const property of type.getProperties()) yield {
|
||||
type: "infer-type",
|
||||
slotName: property.getName(),
|
||||
node: slotsNode
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @param {Type} type
|
||||
* @returns {Iterable<Type>}
|
||||
*/
|
||||
function* iterateTypes(type) {
|
||||
if (isReferenceObject(type) && type.target !== type) yield* iterateTypes(type.target);
|
||||
else if (type.isUnion() && !isBooleanLike(type)) for (const t of type.types) yield* iterateTypes(t);
|
||||
else yield type;
|
||||
}
|
||||
}));
|
||||
|
||||
//#endregion
|
||||
Object.defineProperty(exports, 'default', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return require_ts_types();
|
||||
}
|
||||
});
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
const require_runtime = require('../../_virtual/_rolldown/runtime.js');
|
||||
|
||||
//#region lib/utils/ts-utils/typescript.js
|
||||
var require_typescript = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
|
||||
/**
|
||||
* @typedef {typeof import("typescript")} TypeScript
|
||||
* @typedef {import("typescript").Type} Type
|
||||
* @typedef {import("typescript").ObjectType} ObjectType
|
||||
* @typedef {import("typescript").InterfaceType} InterfaceType
|
||||
* @typedef {import("typescript").TypeReference} TypeReference
|
||||
* @typedef {import("typescript").UnionOrIntersectionType} UnionOrIntersectionType
|
||||
* @typedef {import("typescript").TypeParameter} TypeParameter
|
||||
*/
|
||||
/** @type {TypeScript | undefined} */
|
||||
let cacheTypeScript;
|
||||
module.exports = {
|
||||
getTypeScript,
|
||||
isObject,
|
||||
isAny,
|
||||
isUnknown,
|
||||
isNever,
|
||||
isNull,
|
||||
isFunction,
|
||||
isArrayLikeObject,
|
||||
isStringLike,
|
||||
isNumberLike,
|
||||
isBooleanLike,
|
||||
isBigIntLike,
|
||||
isReferenceObject,
|
||||
extractTypeFlags,
|
||||
extractObjectFlags
|
||||
};
|
||||
/**
|
||||
* Get TypeScript instance
|
||||
*/
|
||||
function getTypeScript() {
|
||||
if (cacheTypeScript) return cacheTypeScript;
|
||||
try {
|
||||
return cacheTypeScript = require("typescript");
|
||||
} catch (error) {
|
||||
if (error.code === "MODULE_NOT_FOUND") return;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* For debug
|
||||
* @param {Type} tsType
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function extractTypeFlags(tsType) {
|
||||
const ts = getTypeScript();
|
||||
/** @type {string[]} */
|
||||
const result = [];
|
||||
const keys = Object.keys(ts.TypeFlags);
|
||||
for (const k of keys) if ((tsType.flags & ts.TypeFlags[k]) !== 0) result.push(k);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* For debug
|
||||
* @param {Type} tsType
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function extractObjectFlags(tsType) {
|
||||
if (!isObject(tsType)) return [];
|
||||
const ts = getTypeScript();
|
||||
/** @type {string[]} */
|
||||
const result = [];
|
||||
const keys = Object.keys(ts.ObjectFlags);
|
||||
for (const k of keys) if ((tsType.objectFlags & ts.ObjectFlags[k]) !== 0) result.push(k);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is an object type or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
* @returns {tsType is ObjectType}
|
||||
*/
|
||||
function isObject(tsType) {
|
||||
const ts = getTypeScript();
|
||||
return (tsType.flags & ts.TypeFlags.Object) !== 0;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is an array-like type or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
*/
|
||||
function isArrayLikeObject(tsType) {
|
||||
const ts = getTypeScript();
|
||||
return isObject(tsType) && (tsType.objectFlags & (ts.ObjectFlags.ArrayLiteral | ts.ObjectFlags.EvolvingArray | ts.ObjectFlags.Tuple)) !== 0;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is an any type or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
*/
|
||||
function isAny(tsType) {
|
||||
const ts = getTypeScript();
|
||||
return (tsType.flags & ts.TypeFlags.Any) !== 0;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is an unknown type or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
*/
|
||||
function isUnknown(tsType) {
|
||||
const ts = getTypeScript();
|
||||
return (tsType.flags & ts.TypeFlags.Unknown) !== 0;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is a never type or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
*/
|
||||
function isNever(tsType) {
|
||||
const ts = getTypeScript();
|
||||
return (tsType.flags & ts.TypeFlags.Never) !== 0;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is an null type or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
*/
|
||||
function isNull(tsType) {
|
||||
const ts = getTypeScript();
|
||||
return (tsType.flags & ts.TypeFlags.Null) !== 0;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is a string-like type or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
* @returns {boolean} `true` if the type is a string-like type.
|
||||
*/
|
||||
function isStringLike(tsType) {
|
||||
const ts = getTypeScript();
|
||||
return (tsType.flags & ts.TypeFlags.StringLike) !== 0;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is an number-like type or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
* @returns {boolean} `true` if the type is a number-like type.
|
||||
*/
|
||||
function isNumberLike(tsType) {
|
||||
const ts = getTypeScript();
|
||||
return (tsType.flags & ts.TypeFlags.NumberLike) !== 0;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is an boolean-like type or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
* @returns {boolean} `true` if the type is a boolean-like type.
|
||||
*/
|
||||
function isBooleanLike(tsType) {
|
||||
const ts = getTypeScript();
|
||||
return (tsType.flags & ts.TypeFlags.BooleanLike) !== 0;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is an bigint-like type or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
* @returns {boolean} `true` if the type is a bigint-like type.
|
||||
*/
|
||||
function isBigIntLike(tsType) {
|
||||
const ts = getTypeScript();
|
||||
return (tsType.flags & ts.TypeFlags.BigIntLike) !== 0;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is a reference type or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
* @returns {tsType is TypeReference} `true` if the type is a reference type.
|
||||
*/
|
||||
function isReferenceObject(tsType) {
|
||||
const ts = getTypeScript();
|
||||
return isObject(tsType) && (tsType.objectFlags & ts.ObjectFlags.Reference) !== 0;
|
||||
}
|
||||
/**
|
||||
* Check if a given type is `function` or not.
|
||||
* @param {Type} tsType The type to check.
|
||||
*/
|
||||
function isFunction(tsType) {
|
||||
const ts = getTypeScript();
|
||||
if (tsType.symbol && (tsType.symbol.flags & (ts.SymbolFlags.Function | ts.SymbolFlags.Method)) !== 0) return true;
|
||||
return tsType.getCallSignatures().length > 0;
|
||||
}
|
||||
}));
|
||||
|
||||
//#endregion
|
||||
Object.defineProperty(exports, 'default', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return require_typescript();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user