Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .tsconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,12 @@
"compilerOptions": {
"module": "ES2020",
"moduleResolution": "node"
}
},
"include": [
"node_modules/@v4fire/core/**/*",
"src/**/*"
],
"files": [
"index.d.ts"
]
}
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ Changelog

_Note: Gaps between patch versions are faulty, broken or test releases._

## v3.??.? (2022-??-??)

#### :rocket: New Feature

* Added the new transformer: class property `build/ts-transformers/class-property`
* Removed warnings from a build process
* Added `jasmine` as a direct dependency
* Updated the `favicons` package

#### :boom: Breaking Change

* Removed the `ts-import` monic module
* Now webpack resolves ts modules imported from `node_modules` natively with aliases
* Refactored `tsconfig`

## v3.34.0 (2023-01-30)

#### :bug: Bug Fix
Expand Down
52 changes: 0 additions & 52 deletions build/monic/ts-import.js

This file was deleted.

6 changes: 6 additions & 0 deletions build/ts-transformers/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Changelog
> - :house: [Internal]
> - :nail_care: [Polish]

## v3.??.? (2022-??-??)

#### :rocket: New Feature

* Added new transformer: class property `build/ts-transformers/class-property`

## v3.23.5 (2022-07-12)

#### :rocket: New Feature
Expand Down
172 changes: 172 additions & 0 deletions build/ts-transformers/class-property.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
'use strict';

/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/

const ts = require('typescript');

/**
* @typedef {import('typescript').TransformationContext} Context
* @typedef {import('typescript').Node} Node
* @typedef {import('typescript').VisitResult} VisitResult
* @typedef {import('typescript').Transformer} Transformer
* @typedef {import('typescript').TypeChecker} TypeChecker
* @typedef {import('typescript').PropertyDeclaration} PropertyDeclaration
* @typedef {import('typescript').ConciseBody} ConciseBody
*/

const primitiveTypes = ['boolean', 'number', 'string', 'null', 'undefined'];

/**
* Wraps an old expression into function
*
* @param {Context} context
* @param {Node} oldInitializerNode
* @returns {ConciseBody}
*/
function createFunctionBody(context, oldInitializerNode) {
const {factory} = context;

return factory.createBlock(
[factory.createReturnStatement(oldInitializerNode)],
true
);
}

/**
* Returns true if the type of the specified node is a primitive
*
* @param {Node} node
* @param {TypeChecker} checker
* @returns {boolean}
*/
const isPropertyDeclarationTypePrimitive = (node, checker) => {
const type = checker.typeToString(checker.getTypeAtLocation(node));

return primitiveTypes.includes(type);
};

/**
* Creates AST for wrapped by function property declaration
*
* @param {Context} context
* @param {Node} oldInitializerNode
* @param {Node} originalNode
* @returns {PropertyDeclaration}
*/
const createPropertyDeclaration = (context, oldInitializerNode, originalNode) => {
const
{factory} = context,
body = createFunctionBody(context, oldInitializerNode),
identifierName = ts.getNameOfDeclaration(originalNode).escapedText;

if (!body) {
return originalNode;
}

return factory.createPropertyDeclaration(
originalNode.decorators,
originalNode.modifiers,
factory.createIdentifier(identifierName),
undefined,
undefined,
factory.createFunctionExpression(
undefined,
undefined,
'__classTransformerWrapFunction__',
undefined,
[],
undefined,
body
)
);
};

/**
* Check is class has given decorator
*
* @param {Node} node
* @param {TypeChecker} checker
* @returns {boolean}
*/
const isClassDecorated = (classNode, decoratorName) => {
const {decorators} = classNode;

const getDecoratorName = (decorator) => (
decorator.expression &&
decorator.expression.expression &&
ts.getEscapedTextOfIdentifierOrLiteral(decorator.expression.expression)
);

return decorators && decorators.length > 0 && decorators.some((item) => getDecoratorName(item) === decoratorName);
};

/**
* Check is given node belongs trait
*
* @param {Node} node
* @param {TypeChecker} checker
* @returns {boolean}
*/
const isTrait = (node) => node.getSourceFile().path.includes('/src/traits/');

/**
* A TypeScript transformer to replace class property default value initializators
* with function call
*
* @param {Context} context
* @returns {Transformer}
* @example
* ```typescript
* class A {
* value = {}
* }
* // Becomes
* class A {
* value = function() { return {} }
* }
*
* class A {
* date = new Date()
* }
* // Becomes
* class A {
* date = function() { return new Date() }
* }
* ```
*/
const classPropertyTransformer = (program) => (context) => {
/**
* @param {Node} node
* @returns {VisitResult}
*/
function visitor(node) {
const typeChecker = program.getTypeChecker();
const ignoredFields = ['traits'];
const identifierName = ts.getNameOfDeclaration(node) && ts.getNameOfDeclaration(node).escapedText;

if (
ts.isPropertyDeclaration(node) &&
!ignoredFields.some((fieldName) => fieldName === identifierName) &&
node.parent && ts.isClassDeclaration(node.parent) &&
node.parent.decorators && node.parent.decorators.length > 0 &&
(isClassDecorated(node.parent, 'component') || isTrait(node)) &&
ts.hasInitializer(node) && !isPropertyDeclarationTypePrimitive(node, typeChecker)
) {
const initializer = ts.getEffectiveInitializer(node);

return createPropertyDeclaration(context, initializer, node);
}

return ts.visitEachChild(node, visitor, context);
}

return (node) => ts.visitNode(node, visitor);
};

module.exports = classPropertyTransformer;
19 changes: 11 additions & 8 deletions build/ts-transformers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/

const modernRegExpFlagsTransformer = include('build/ts-transformers/modern-regexp-flags');
const
modernRegExpFlagsTransformer = include('build/ts-transformers/modern-regexp-flags'),
classPropertyTransformer = include('build/ts-transformers/class-property');

module.exports = {
before: {
modernRegExpFlagsTransformer
},
module.exports = (program) => ({
before: [
modernRegExpFlagsTransformer(program),
classPropertyTransformer(program)
],

after: {},
after: [],

afterDeclarations: {}
};
afterDeclarations: []
});
8 changes: 4 additions & 4 deletions build/ts-transformers/modern-regexp-flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ const ts = require('typescript');
* new RegExp('\\W+', 'su');
* ```
*/
function modernRegExpFlagsTransformer(context) {
const modernRegExpFlagsTransformer = (context) => {
const modernRegExpFlags = ['s', 'y', 'u'];

/**
* @param {Node} node
* @returns {VisitResult}
*/
function visitor(node) {
if (node.kind === ts.SyntaxKind.RegularExpressionLiteral) {
if (ts.isRegularExpressionLiteral(node)) {
const
lastSlash = node.text.lastIndexOf('/'),
flags = node.text.slice(lastSlash + 1),
Expand All @@ -65,6 +65,6 @@ function modernRegExpFlagsTransformer(context) {
}

return (node) => ts.visitNode(node, visitor);
}
};

module.exports = modernRegExpFlagsTransformer;
module.exports = () => modernRegExpFlagsTransformer;
5 changes: 2 additions & 3 deletions build/webpack/alias.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,15 @@ const
* Options for `webpack.alias`
*/
const aliases = {
'@super': resolve.rootDependencies[0],
...$C(pzlr.dependencies).to({}).reduce((map, el, i) => {
...$C(pzlr.dependencies).to({}).reduce((map, el) => {
const
asset = resolve.depMap[el].config.assets;

if (asset?.sprite == null) {
return map;
}

map[`${el}/sprite`] = path.join(resolve.rootDependencies[i], asset.dir, asset.sprite);
map[`${el}/sprite`] = path.join(resolve.depMap[el].src, asset.dir, asset.sprite);
return map;
})
};
Expand Down
Loading