diff --git a/src/target-php/index.ts b/src/target-php/index.ts index 30274e80..ee20c168 100644 --- a/src/target-php/index.ts +++ b/src/target-php/index.ts @@ -1,6 +1,6 @@ import { getInlineDeclarations } from '../parsers/dependency-resolver' import { keyBy } from 'lodash' -import { isReserved } from './util' +import { isReserved } from './utils/lang' import { Modules, generatePHPCode } from './compilers/ts2php' import { transformAstToPHP } from './transformers/index' import { Project } from 'ts-morph' diff --git a/src/target-php/transformers/index.ts b/src/target-php/transformers/index.ts index 53d488db..b85e73e5 100644 --- a/src/target-php/transformers/index.ts +++ b/src/target-php/transformers/index.ts @@ -1,4 +1,5 @@ -import { isReserved, removeObjectLiteralInitiator } from '../util' +import { isReserved } from '../utils/lang' +import { refactorMemberInitializer } from './refactor-member-initializer' import { SanSourceFile } from '../..' import { refactorFiltersProperty } from './refactor-filters-property' import { refactorComputedProperty } from './refactor-computed-property' @@ -26,7 +27,7 @@ export function transformAstToPHP (sourceFile: SanSourceFile) { } else if (prop.getName() === 'filters') { refactorFiltersProperty(prop, sanssr) } - removeObjectLiteralInitiator(sourceFile.tsSourceFile, clazz, prop) + refactorMemberInitializer(clazz, prop) } } diff --git a/src/target-php/transformers/refactor-member-initializer.ts b/src/target-php/transformers/refactor-member-initializer.ts new file mode 100644 index 00000000..32d59296 --- /dev/null +++ b/src/target-php/transformers/refactor-member-initializer.ts @@ -0,0 +1,25 @@ +import { ClassDeclaration, TypeGuards, Expression, PropertyDeclaration } from 'ts-morph' + +export function refactorMemberInitializer (clazz: ClassDeclaration, prop: PropertyDeclaration) { + const initializer = prop.getInitializer() + if (!initializer || isConstant(initializer)) return + + if (prop.isStatic()) { + const statement = clazz.getName() + '.' + prop.getName() + ' = ' + initializer.getFullText() + clazz.getSourceFile().addStatements(statement) + } else { + let statement = 'this.' + prop.getName() + ' = ' + initializer.getFullText() + if (!clazz.getConstructors().length) { + clazz.addConstructor() + statement = 'super()\n' + statement + } + const init = clazz.getConstructors()[0] + init.setBodyText(init.getBodyText() + '\n' + statement) + } + prop.removeInitializer() +} + +function isConstant (expr: Expression) { + if (TypeGuards.isLiteralExpression(expr)) return true + return false +} diff --git a/src/target-php/util.ts b/src/target-php/util.ts deleted file mode 100644 index edbb1a1b..00000000 --- a/src/target-php/util.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { SourceFile, ClassDeclaration, TypeGuards, Expression, PropertyDeclaration } from 'ts-morph' - -const reservedNames = [/^list$/i] - -export function isObjectLiteralExpression (expr: Expression) { - if (TypeGuards.isObjectLiteralExpression(expr)) return true - if (TypeGuards.isAsExpression(expr) && TypeGuards.isObjectLiteralExpression(expr.getExpression())) return true - return false -} - -export function removeObjectLiteralInitiator (sourceFile: SourceFile, clazz: ClassDeclaration, prop: PropertyDeclaration) { - const initializer = prop.getInitializer() - if (!initializer || !isObjectLiteralExpression(initializer)) return - - if (prop.isStatic()) { - const statement = clazz.getName() + '.' + prop.getName() + ' = ' + initializer.getFullText() - sourceFile.addStatements(statement) - } else { - let statement = 'this.' + prop.getName() + ' = ' + initializer.getFullText() - if (!clazz.getConstructors().length) { - clazz.addConstructor() - statement = 'super()\n' + statement - } - const init = clazz.getConstructors()[0] - init.setBodyText(init.getBodyText() + '\n' + statement) - } - prop.removeInitializer() -} - -export function isReserved (name: string) { - for (const reserved of reservedNames) { - if (reserved.test(name)) return true - } - return false -} diff --git a/src/target-php/utils/lang.ts b/src/target-php/utils/lang.ts new file mode 100644 index 00000000..055a28c8 --- /dev/null +++ b/src/target-php/utils/lang.ts @@ -0,0 +1,8 @@ +const reservedNames = [/^list$/i] + +export function isReserved (name: string) { + for (const reserved of reservedNames) { + if (reserved.test(name)) return true + } + return false +} diff --git a/test/cases/property-initializer/component.ts b/test/cases/property-initializer/component.ts new file mode 100644 index 00000000..43ab9e08 --- /dev/null +++ b/test/cases/property-initializer/component.ts @@ -0,0 +1,12 @@ +import { Component } from 'san' + +const TEMPLATE = '
{{title | real}}
' + +export default class MyComponent extends Component { + static template = TEMPLATE + static filters = { + real: function (x) { + return 'real' + x + } + } +} diff --git a/test/cases/property-initializer/data.json b/test/cases/property-initializer/data.json new file mode 100644 index 00000000..6308511a --- /dev/null +++ b/test/cases/property-initializer/data.json @@ -0,0 +1,3 @@ +{ + "title": "1" +} \ No newline at end of file diff --git a/test/cases/property-initializer/result.html b/test/cases/property-initializer/result.html new file mode 100644 index 00000000..11643cb1 --- /dev/null +++ b/test/cases/property-initializer/result.html @@ -0,0 +1 @@ +
real1
\ No newline at end of file diff --git a/test/cases/property-initializer/spec.js b/test/cases/property-initializer/spec.js new file mode 100644 index 00000000..8eed1d23 --- /dev/null +++ b/test/cases/property-initializer/spec.js @@ -0,0 +1,7 @@ +it('method', function () { + // [inject] init + + const b = wrap.getElementsByTagName('b')[0] + + expect(b.title).toBe('real1') +}) diff --git a/test/unit/target-php/refactor-member-initializer.ts b/test/unit/target-php/refactor-member-initializer.ts new file mode 100644 index 00000000..76fb0655 --- /dev/null +++ b/test/unit/target-php/refactor-member-initializer.ts @@ -0,0 +1,73 @@ +import { refactorMemberInitializer } from '../../../src/target-php/transformers/refactor-member-initializer' +import { Project } from 'ts-morph' + +describe('refactorMemberInitializer()', function () { + const project = new Project() + + it('should skip string literal static initializer', function () { + const sourceFile = project.createSourceFile('/tmp/static-str-literal', ` + class Foo { + static staticLiteralStr: string = "foo" + }`) + const clazz = sourceFile.getClass('Foo') + for (const prop of clazz.getProperties()) { + refactorMemberInitializer(clazz, prop) + } + sourceFile.formatText() + const text = sourceFile.getFullText() + + expect(text).toContain(`static staticLiteralStr: string = "foo"`) + expect(text).not.toContain(`Foo.staticLiteralStr =`) + }) + + it('should refactor string variable static initializer', function () { + const sourceFile = project.createSourceFile('/tmp/static-str-var', ` + const str = "foo" + class Foo { + static staticLiteralStr: string = str + }`) + const clazz = sourceFile.getClass('Foo') + for (const prop of clazz.getProperties()) { + refactorMemberInitializer(clazz, prop) + } + sourceFile.formatText() + const text = sourceFile.getFullText() + + expect(text).toContain(`static staticLiteralStr: string`) + expect(text).toContain(`Foo.staticLiteralStr = str`) + }) + + it('should skip string literal initializer', function () { + const sourceFile = project.createSourceFile('/tmp/str-literal', ` + class Foo { + literalStr: string = "str" + }`) + const clazz = sourceFile.getClass('Foo') + for (const prop of clazz.getProperties()) { + refactorMemberInitializer(clazz, prop) + } + const text = sourceFile.getFullText() + + expect(text).toContain(`literalStr: string = "str"`) + expect(text).not.toContain(`constructor()`) + }) + + it('should refactor string literal initializer', function () { + const sourceFile = project.createSourceFile('/tmp/str-var', ` + const str = "foo" + class Foo { + literalStr: string = str + }`) + const clazz = sourceFile.getClass('Foo') + for (const prop of clazz.getProperties()) { + refactorMemberInitializer(clazz, prop) + } + sourceFile.formatText() + const text = sourceFile.getFullText() + + expect(text).toContain(`literalStr: string\n`) + expect(text).toContain(`constructor() {`) + expect(text).toContain(`super()`) + expect(text).toContain(`this.literalStr = str`) + }) +})