diff --git a/bin/render.php b/bin/render.php index 75f92a53..971d8905 100755 --- a/bin/render.php +++ b/bin/render.php @@ -7,7 +7,7 @@ $data = getData($caseDir); $noDataOutput = preg_match('/-ndo$/', $caseName); -$renderFunc = '\\san\\renderer\\' . dashesToCamelCase($caseName) . '\\render'; +$renderFunc = '\\san\\' . dashesToCamelCase($caseName) . '\\renderer\\render'; echo $renderFunc($data, $noDataOutput); diff --git a/runtime/underscore.php b/runtime/underscore.php index 1a83ba4b..f56c72d7 100644 --- a/runtime/underscore.php +++ b/runtime/underscore.php @@ -179,8 +179,8 @@ private static function boolAttrTruthy($value) { public static function getClassByCtx($ctx) { $cid = $ctx->sanssrCid; - if (\san\runtime\ComponentRegistry::has($cid)) { - return \san\runtime\ComponentRegistry::get($cid); + if (\__NSPREFIX__runtime\ComponentRegistry::has($cid)) { + return \__NSPREFIX__runtime\ComponentRegistry::get($cid); } return null; } @@ -196,7 +196,7 @@ public static function callFilter($ctx, $name, $args) public static function createComponent (&$ctx) { $cls = _::getClassByCtx($ctx); if (!class_exists($cls)) { - $cls = "\\san\\runtime\\Component"; + $cls = '\__NSPREFIX__runtime\Component'; } $obj = new $cls(); $obj->data = new Data($ctx); diff --git a/src/compilers/component-registry.ts b/src/compilers/component-registry.ts index 2efc25c6..80c70868 100644 --- a/src/compilers/component-registry.ts +++ b/src/compilers/component-registry.ts @@ -18,15 +18,15 @@ export class ComponentRegistry { } } - writeComponentRegistry (ns: (file: string) => string, emitter: PHPEmitter) { - emitter.beginNamespace('san\\runtime') + writeComponentRegistry (nsPrefix: string, ns: (file: string) => string, emitter: PHPEmitter) { + emitter.beginNamespace(`${nsPrefix}runtime`) emitter.writeLine(`ComponentRegistry::$comps = [`) emitter.indent() const lines = [] for (const [cid, { name, path }] of this.components) { - const classReference = `\\${ns(path)}\\${name}` - lines.push(`"${cid}" => "${classReference.replace(/\\/g, '\\\\')}"`) + const classReference = `\\${nsPrefix}${ns(path)}\\${name}` + lines.push(`"${cid}" => '${classReference}'`) } emitter.writeLines(lines.join(',\n')) diff --git a/src/compilers/php-render-compiler.ts b/src/compilers/php-render-compiler.ts index 2633fe58..ec76698e 100644 --- a/src/compilers/php-render-compiler.ts +++ b/src/compilers/php-render-compiler.ts @@ -6,6 +6,9 @@ import { each, extend } from '../utils/underscore' import { PHPEmitter } from '../emitters/php-emitter' import { ExpressionEmitter } from '../emitters/expression-emitter' +let ssrIndex = 0 +let namespacePrefix = '' + /** * 将字符串逗号切分返回对象 * @@ -395,8 +398,6 @@ function camelComponentBinds (binds) { return result } -let ssrIndex = 0 - function genSSRId () { return 'sanssrId' + (ssrIndex++) } @@ -445,7 +446,7 @@ const stringifier = { }, date: function (source) { - return 'new \\san\\runtime\\Ts2Php_Date(' + source.getTime() + ')' + return `new \\${namespacePrefix}runtime\\Ts2Php_Date(` + source.getTime() + ')' }, any: function (source) { @@ -1192,14 +1193,15 @@ function genComponentContextCode (component, emitter) { export function generateRenderModule ({ ComponentClass, funcName = '', - ns = 'san\\renderer', + nsPrefix = '', emitter = new PHPEmitter() }) { + namespacePrefix = nsPrefix if (typeof ComponentClass !== 'function') { throw new Error('ComponentClass is needed to generate render function') } - emitter.beginNamespace(ns) - emitter.writeLine(`use \\san\\runtime\\_;`) + emitter.beginNamespace(nsPrefix + 'renderer') + emitter.writeLine(`use ${nsPrefix}runtime\\_;`) ssrIndex = 0 const contextId = genSSRId() diff --git a/src/compilers/to-js-compiler.ts b/src/compilers/to-js-compiler.ts index 75eaffde..ac5b5150 100644 --- a/src/compilers/to-js-compiler.ts +++ b/src/compilers/to-js-compiler.ts @@ -10,6 +10,7 @@ import { getDefaultConfigPath } from '../parsers/tsconfig' import { sep, extname } from 'path' import debugFactory from 'debug' import { Compiler } from './compiler' +import { emitRuntimeInJS } from '../emitters/runtime' const debug = debugFactory('to-js-compiler') @@ -48,7 +49,7 @@ export class ToJSCompiler implements Compiler { const emitter = new JSEmitter() emitter.write('module.exports = ') emitter.writeAnonymousFunction(['data', 'noDataOutput'], () => { - emitter.writeRuntime() + emitRuntimeInJS(emitter) const componentClass = new CommonJS().require(filepath) emitter.writeLines(generateRenderFunction(componentClass)) }) @@ -60,7 +61,7 @@ export class ToJSCompiler implements Compiler { const emitter = new JSEmitter() emitter.write('module.exports = ') emitter.writeAnonymousFunction(['data', 'noDataOutput'], () => { - emitter.writeRuntime() + emitRuntimeInJS(emitter) const parser = new ComponentParser(this.project) const component = parser.parseComponent(filepath) const componentClass = this.evalComponentClass(component) diff --git a/src/compilers/to-php-compiler.ts b/src/compilers/to-php-compiler.ts index a3135c4e..456b071f 100644 --- a/src/compilers/to-php-compiler.ts +++ b/src/compilers/to-php-compiler.ts @@ -16,20 +16,19 @@ import { getDefaultConfigPath } from '../parsers/tsconfig' import { sep, extname } from 'path' import debugFactory from 'debug' import { Compiler } from './compiler' +import { emitRuntimeInPHP } from '../emitters/runtime' const debug = debugFactory('ast-util') export type ToPHPCompilerOptions = { tsConfigFilePath?: string, root?: string, - externalModules?: ModuleInfo[], - nsPrefix?: string + externalModules?: ModuleInfo[] } export class ToPHPCompiler implements Compiler { private root: string private tsConfigFilePath: string - private nsPrefix: string private externalModules: ModuleInfo[] private toJSCompiler: ToJSCompiler private project: Project @@ -37,10 +36,8 @@ export class ToPHPCompiler implements Compiler { constructor ({ tsConfigFilePath = getDefaultConfigPath(), root = tsConfigFilePath.split(sep).slice(0, -1).join(sep), - externalModules = [], - nsPrefix = '' + externalModules = [] }: ToPHPCompilerOptions = {}) { - this.nsPrefix = nsPrefix this.externalModules = [{ name: 'san-ssr', required: true @@ -67,7 +64,7 @@ export class ToPHPCompiler implements Compiler { public compileFromTS (filepath: string, { funcName = 'render', - ns = 'san\\renderer', + nsPrefix = 'san\\', emitHeader = true } = {}) { const emitter = new PHPEmitter(emitHeader) @@ -75,33 +72,33 @@ export class ToPHPCompiler implements Compiler { const component = parser.parseComponent(filepath) const ComponentClass = this.toJSCompiler.evalComponentClass(component) - generateRenderModule({ ComponentClass, funcName, emitter, ns }) - this.compileComponents(component, emitter) + generateRenderModule({ ComponentClass, funcName, emitter, nsPrefix }) + this.compileComponents(component, emitter, nsPrefix) - emitter.writeRuntime() + emitRuntimeInPHP(emitter, nsPrefix) return emitter.fullText() } public compileFromJS (filepath: string, { funcName = 'render', - ns = 'san\\renderer', + nsPrefix = 'san\\', emitHeader = true } = {}) { const emitter = new PHPEmitter(emitHeader) const ComponentClass = new CommonJS().require(filepath) - generateRenderModule({ ComponentClass, funcName, emitter, ns }) + generateRenderModule({ ComponentClass, funcName, emitter, nsPrefix }) - emitter.writeRuntime() + emitRuntimeInPHP(emitter, nsPrefix) return emitter.fullText() } - public compileToPHP (sourceFile: SanSourceFile) { + public compileToPHP (sourceFile: SanSourceFile, nsPrefix = '') { transformAstToPHP(sourceFile) const tsconfig = require(this.tsConfigFilePath) const externalModules = [...this.externalModules] for (const decl of getInlineDeclarations(sourceFile.origin)) { - const ns = this.ns(decl.getModuleSpecifierSourceFile().getFilePath()) + const ns = nsPrefix + this.ns(decl.getModuleSpecifierSourceFile().getFilePath()) const literal = decl.getModuleSpecifierValue() externalModules.push({ name: literal, @@ -112,34 +109,31 @@ export class ToPHPCompiler implements Compiler { return generatePHPCode( sourceFile, externalModules, - tsconfig['compilerOptions'] + tsconfig['compilerOptions'], + nsPrefix ) } - public compileComponents (entryComp: Component, emitter: PHPEmitter = new PHPEmitter()) { + public compileComponents (entryComp: Component, emitter: PHPEmitter = new PHPEmitter(), nsPrefix = '') { const registry = new ComponentRegistry() for (const [path, sourceFile] of entryComp.getFiles()) { registry.registerComponents(sourceFile) - emitter.beginNamespace(this.ns(path)) - emitter.writeLine('use \\san\\runtime\\_;') - emitter.writeLine('use \\san\\runtime\\Component;') - emitter.writeLines(this.compileToPHP(sourceFile)) + emitter.beginNamespace(nsPrefix + this.ns(path)) + emitter.writeLine(`use ${nsPrefix}runtime\\_;`) + emitter.writeLine(`use ${nsPrefix}runtime\\Component;`) + emitter.writeLines(this.compileToPHP(sourceFile, nsPrefix)) emitter.endNamespace() } - registry.writeComponentRegistry(path => this.ns(path), emitter) + registry.writeComponentRegistry(nsPrefix, path => this.ns(path), emitter) return emitter.fullText() } - private ns (file) { + private ns (file: string) { const escapeName = x => isReserved(x) ? 'sanssrNS' + camelCase(x) : x - let str = file + return file .slice(this.root.length, -extname(file).length) - .split(sep).map(camelCase).map(escapeName).join('\\') + .split(sep).map(x => camelCase(x)).map(escapeName).join('\\') .replace(/^\\/, '') - if (this.nsPrefix) { - str = this.nsPrefix + str - } - return str } } diff --git a/src/emitters/emitter.ts b/src/emitters/emitter.ts index f1c9971e..c9228eed 100644 --- a/src/emitters/emitter.ts +++ b/src/emitters/emitter.ts @@ -8,7 +8,6 @@ export abstract class Emitter { } public abstract write (str: string) - public abstract writeRuntime () public fullText () { return this.code } diff --git a/src/emitters/generate-php-code.ts b/src/emitters/generate-php-code.ts index 26ec275a..27797443 100644 --- a/src/emitters/generate-php-code.ts +++ b/src/emitters/generate-php-code.ts @@ -11,14 +11,14 @@ export type ModuleInfo = { namespace?: string } -export function generatePHPCode (sourceFile: SanSourceFile, modules: ModuleInfo[], compilerOptions) { +export function generatePHPCode (sourceFile: SanSourceFile, modules: ModuleInfo[], compilerOptions, nsPrefix: string) { debug('modules:', modules) const options = { source: sourceFile.getFullText(), emitHeader: false, plugins: [], modules: keyBy(modules, 'name'), - helperNamespace: '\\san\\runtime\\', + helperNamespace: `\\${nsPrefix}runtime\\`, compilerOptions } const { errors, phpCode } = compile(sourceFile.getFilePath(), options) diff --git a/src/emitters/js-emitter.ts b/src/emitters/js-emitter.ts index 2578fcbe..c08c9efc 100644 --- a/src/emitters/js-emitter.ts +++ b/src/emitters/js-emitter.ts @@ -1,11 +1,6 @@ import { Emitter } from './emitter' -import { emitRuntimeInJS } from './runtime' export class JSEmitter extends Emitter { - public writeRuntime () { - emitRuntimeInJS(this) - } - public write (str: string) { return this.defaultWrite(str) } diff --git a/src/emitters/php-emitter.ts b/src/emitters/php-emitter.ts index 05700886..ad3c8b2e 100644 --- a/src/emitters/php-emitter.ts +++ b/src/emitters/php-emitter.ts @@ -1,6 +1,5 @@ import { Emitter } from './emitter' import { ExpressionEmitter } from './expression-emitter' -import { emitRuntimeInPHP } from './runtime' export class PHPEmitter extends Emitter { buffer: string = '' @@ -15,10 +14,6 @@ export class PHPEmitter extends Emitter { return this.defaultWrite(str) } - public writeRuntime () { - emitRuntimeInPHP(this) - } - public beginNamespace (ns: string = '') { const code = ns === '' ? 'namespace {' diff --git a/src/emitters/runtime.ts b/src/emitters/runtime.ts index 03aa87f7..5830dcd0 100644 --- a/src/emitters/runtime.ts +++ b/src/emitters/runtime.ts @@ -10,11 +10,11 @@ const runtimeFiles = [ 'component-registry.php' ] -export function emitRuntimeInPHP (emitter: PHPEmitter) { - emitter.beginNamespace('san\\runtime') +export function emitRuntimeInPHP (emitter: PHPEmitter, nsPrefix: string) { + emitter.beginNamespace(nsPrefix + 'runtime') for (const file of runtimeFiles) { const path = resolve(__dirname, `../../runtime/${file}`) - emitter.writeLines(readPHPSource(path)) + emitter.writeLines(readPHPSource(path).replace(/__NSPREFIX__/g, nsPrefix)) } emitter.endNamespace() return emitter.fullText() diff --git a/src/utils/case.ts b/src/utils/case.ts index f3784f6a..58333a1e 100644 --- a/src/utils/case.ts +++ b/src/utils/case.ts @@ -14,8 +14,7 @@ const cases = readdirSync(caseRoot) const toJSCompiler = new ToJSCompiler({ tsConfigFilePath }) const toPHPCompiler = new ToPHPCompiler({ tsConfigFilePath, - externalModules: [{ name: '../../..', required: true }], - nsPrefix: 'san\\components\\test\\' + externalModules: [{ name: '../../..', required: true }] }) const multiFileCases = ['multi-component-files', 'multi-files'] @@ -41,7 +40,7 @@ export function compileToPHP (caseName) { const js = resolve(caseRoot, caseName, 'component.js') const targetCode = toPHPCompiler.compile( existsSync(ts) ? ts : js, - { ns: `san\\renderer\\${camelCase(caseName)}` } + { nsPrefix: `san\\${camelCase(caseName)}\\` } ) writeFileSync(join(caseRoot, caseName, 'ssr.php'), targetCode)