Skip to content

Commit

Permalink
feat(providence): allow to run with swc; make all analyzers compatibl…
Browse files Browse the repository at this point in the history
…e with swc
  • Loading branch information
tlouisse committed Feb 6, 2025
1 parent 22b8f24 commit fd2e799
Show file tree
Hide file tree
Showing 33 changed files with 2,577 additions and 3,320 deletions.
5 changes: 5 additions & 0 deletions .changeset/smart-hairs-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'providence-analytics': patch
---

allow to run with swc; make all analyzers compatible with swc
35 changes: 18 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions packages-node/providence-analytics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,18 @@
"commander": "^2.20.3",
"oxc-parser": "0.48.2",
"parse5": "^7.2.1",
"semver": "^7.7.0"
"semver": "^7.7.1"
},
"peerDependencies": {
"@babel/parser": "^7.25.8",
"@babel/plugin-syntax-import-assertions": "^7.25.7",
"@swc/core": "^1.7.36"
"@swc/core": "^1.10.14"
},
"devDependencies": {
"@babel/parser": "^7.26.7",
"@babel/plugin-syntax-import-assertions": "^7.26.0",
"@babel/traverse": "^7.26.7",
"@swc/core": "^1.10.12",
"@swc/core": "^1.10.14",
"@types/inquirer": "^9.0.7",
"@types/mocha": "^10.0.10",
"@web/dev-server": "^0.4.6",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
/* eslint-disable no-shadow, no-param-reassign */
import path from 'path';

import { oxcTraverse, isProperty } from '../utils/oxc-traverse.js';

import { trackDownIdentifierFromScope } from '../utils/track-down-identifier.js';
import {
expressionOf,
isProperty,
isSetter,
isGetter,
isStatic,
nameOf,
idOf,
} from '../utils/ast-normalizations.js';
import { oxcTraverse } from '../utils/oxc-traverse.js';
import { Analyzer } from '../core/Analyzer.js';

import { isCustomElementsGet } from './find-customelements.js';

/**
* @typedef {import('@babel/types').File} File
* @typedef {import('@babel/types').ClassMethod} ClassMethod
Expand All @@ -16,22 +26,27 @@ import { Analyzer } from '../core/Analyzer.js';
* @typedef {import('../../../types/index.js').FindClassesAnalyzerEntry} FindClassesAnalyzerEntry
* @typedef {import('../../../types/index.js').FindClassesConfig} FindClassesConfig
* @typedef {import('../../../types/index.js').AnalyzerAst} AnalyzerAst
* @typedef {import("@swc/core").Node} SwcNode
*/

/**
* Finds import specifiers and sources
* @param {File} babelAst
* @param {File} oxcAst
* @param {string} fullCurrentFilePath the file being currently processed
*/
async function findMembersPerAstEntry(babelAst, fullCurrentFilePath, projectPath) {
async function findMembersPerAstEntry(oxcAst, fullCurrentFilePath, projectPath) {
// The transformed entry
const classesFound = [];
/**
* Detects private/publicness based on underscores. Checks '$' as well
* @param {string} name
* @returns {'public'|'protected'|'private'}
* @returns {'public'|'protected'|'private'|'[n/a]'}
*/
function computeAccessType(name) {
if (name === 'constructor') {
return '[n/a]';
}

if (name.startsWith('_') || name.startsWith('$')) {
// (at least) 2 prefixes
if (name.startsWith('__') || name.startsWith('$$')) {
Expand All @@ -47,7 +62,7 @@ async function findMembersPerAstEntry(babelAst, fullCurrentFilePath, projectPath
* @returns
*/
function isStaticProperties({ node }) {
return node.static && node.kind === 'get' && node.key.name === 'properties';
return isStatic(node) && isGetter(node) && nameOf(node.key) === 'properties';
}

// function isBlacklisted({ node }) {
Expand Down Expand Up @@ -86,26 +101,47 @@ async function findMembersPerAstEntry(babelAst, fullCurrentFilePath, projectPath
// }

/**
*
* @param {SwcNode|OxcNode} node
*/
function isSuperClassAMixin(superClassNode) {
if (!superClassNode) return false;

const isCallExpression = superClassNode?.type === 'CallExpression';
if (!isCallExpression) return false;
return !isCustomElementsGet(superClassNode.callee);
}

/**
* @param {NodePath} astPath
* @param {{isMixin?:boolean}} opts
*/
async function traverseClass(astPath, { isMixin = false } = {}) {
const classRes = {};
classRes.name = astPath.node.id && astPath.node.id.name;
classRes.name = (idOf(astPath.node) && nameOf(idOf(astPath.node))) || null;
classRes.isMixin = Boolean(isMixin);

if (astPath.node.superClass) {
const superClasses = [];

// Add all Identifier names
let parent = astPath.node.superClass;
while (parent.type === 'CallExpression') {
superClasses.push({ name: parent.callee.name, isMixin: true });
while (isSuperClassAMixin(parent)) {
superClasses.push({ name: nameOf(parent.callee), isMixin: true });
// As long as we are a CallExpression, we will have a parent
[parent] = parent.arguments;
[parent] = parent.arguments.map(expressionOf);
}

// At the end of the chain, we find type === Identifier or customElements.get directly.
if (isCustomElementsGet(parent.callee)) {
superClasses.push({
name: null,
customElementsGetRef: nameOf(parent.arguments?.map(expressionOf)[0]),
isMixin: false,
});
} else {
// an identifier like 'MyClass'
superClasses.push({ name: nameOf(expressionOf(parent)), isMixin: false });
}
// At the end of the chain, we find type === Identifier
superClasses.push({ name: parent.name, isMixin: false });

// For all found superclasses, track down their root location.
// This will either result in a local, relative astPath in the project,
Expand Down Expand Up @@ -160,19 +196,27 @@ async function findMembersPerAstEntry(babelAst, fullCurrentFilePath, projectPath
}

const methodRes = {};
const { name } = astPath.node.key;
const name = nameOf(astPath.node.key);
methodRes.name = name;
methodRes.accessType = computeAccessType(name);
if (
['constructor', 'connectedCallback', 'disconnectedCallback', 'adoptedCallback'].includes(
name,
)
) {
methodRes.isPartOfPlatformLifeCycle = true;
}

if (astPath.node.kind === 'set' || astPath.node.kind === 'get') {
if (astPath.node.static) {
if (isSetter(astPath.node) || isGetter(astPath.node)) {
const setOrGet = isSetter(astPath.node) ? 'set' : 'get';
if (isStatic(astPath.node)) {
methodRes.static = true;
}
methodRes.kind = [...(methodRes.kind || []), astPath.node.kind];
methodRes.kind = [...(methodRes.kind || []), setOrGet];
// Merge getter/setters into one
const found = classRes.members.props.find(p => p.name === name);
const found = classRes.members.props.find(p => nameOf(p) === name);
if (found) {
found.kind = [...(found.kind || []), astPath.node.kind];
found.kind = [...(found.kind || []), setOrGet];
} else {
classRes.members.props.push(methodRes);
}
Expand All @@ -184,14 +228,16 @@ async function findMembersPerAstEntry(babelAst, fullCurrentFilePath, projectPath
astPath.traverse({
ClassMethod: handleMethodDefinitionOrClassMethod,
MethodDefinition: handleMethodDefinitionOrClassMethod,
// for swc
Constructor: handleMethodDefinitionOrClassMethod,
});

classesFound.push(classRes);
}

const classesToTraverse = [];

oxcTraverse(babelAst, {
oxcTraverse(oxcAst, {
ClassDeclaration(astPath) {
classesToTraverse.push({ astPath, isMixin: false });
},
Expand Down
Loading

0 comments on commit fd2e799

Please sign in to comment.