Skip to content

Commit

Permalink
Refactoring readTemplate and readStyle to use Maybe<T>
Browse files Browse the repository at this point in the history
  • Loading branch information
ghsyeung committed Dec 29, 2016
1 parent ba0f67f commit 373b152
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 174 deletions.
249 changes: 120 additions & 129 deletions src/angular/metadataReader.ts
Expand Up @@ -8,19 +8,22 @@ import {logger} from '../util/logger';

import {Config} from './config';

import {DirectiveMetadata, ComponentMetadata, CodeWithSourceMap, TemplateMetadata} from './metadata';
import {Maybe, unwrapFirst, ifTrue,} from '../util/function';
import {
callExpression, withIdentifier, hasProperties,
isSimpleTemplateString, getStringInitializerFromProperty, decoratorArgument
DirectiveMetadata, ComponentMetadata, CodeWithSourceMap, TemplateMetadata, StylesMetadata,
StyleMetadata
} from './metadata';
import {Maybe, unwrapFirst, ifTrue, listToMaybe,} from '../util/function';
import {
callExpression, withIdentifier, hasProperties,
isSimpleTemplateString, getStringInitializerFromProperty, decoratorArgument
} from '../util/astQuery';
import {getTemplate, getInlineStyle} from '../util/ngQuery';

const normalizeTransformed = (t: CodeWithSourceMap) => {
if (!t.map) {
t.source = t.code;
}
return t;
if (!t.map) {
t.source = t.code;
}
return t;
};


Expand All @@ -29,127 +32,115 @@ const normalizeTransformed = (t: CodeWithSourceMap) => {
*/
export class MetadataReader {

constructor(private _fileResolver: FileResolver, private _urlResolver?: AbstractResolver) {
this._urlResolver = this._urlResolver || new UrlResolver(new PathResolver());
}

read(d: ts.ClassDeclaration): DirectiveMetadata {
let componentMetadata = unwrapFirst(
(d.decorators || ([] as ts.Decorator[])).map((dec: ts.Decorator) => {
return Maybe.lift(dec).bind(callExpression)
.bind(withIdentifier('Component'))
.fmap(() => this.readComponentMetadata(d, dec));
}));

let directiveMetadata = unwrapFirst(
(d.decorators || ([] as ts.Decorator[])).map((dec: ts.Decorator) =>
Maybe.lift(dec)
.bind(callExpression)
.bind(withIdentifier('Directive'))
.fmap(() => this.readDirectiveMetadata(d, dec))
));

return directiveMetadata || componentMetadata || undefined;
}

readDirectiveMetadata(d: ts.ClassDeclaration, dec: ts.Decorator): DirectiveMetadata {

const selector = this.getDecoratorArgument(dec)
.bind(expr => getStringInitializerFromProperty('selector', expr.properties))
.fmap(initializer => initializer.text);

return Object.assign(new DirectiveMetadata(), {
controller: d,
decorator: dec,
selector: selector.unwrap(),
});
}

readComponentTemplateMetadata(dec: ts.Decorator, external: MetadataUrls): TemplateMetadata {
const template_M = getTemplate(dec)
.fmap(inlineTemplate => {
const transformed = normalizeTransformed(Config.transformTemplate(inlineTemplate.text, null, dec));
return {
template: transformed,
url: null,
node: inlineTemplate,
};
});

if (template_M.isSomething) {
return template_M.unwrap();
} else {
// TODO: Refactoring this requires adding seem to fileResolver
if (external.templateUrl) {
try {
const template = this._fileResolver.resolve(external.templateUrl);
const transformed = normalizeTransformed(Config.transformTemplate(template, external.templateUrl, dec));
return {
template: transformed,
url: external.templateUrl,
node: null
};
} catch (e) {
logger.info('Cannot read the external template ' + external.templateUrl);
}
}
constructor(private _fileResolver: FileResolver, private _urlResolver?: AbstractResolver) {
this._urlResolver = this._urlResolver || new UrlResolver(new PathResolver());
}

read(d: ts.ClassDeclaration): DirectiveMetadata {
let componentMetadata = unwrapFirst(
(d.decorators || ([] as ts.Decorator[])).map((dec: ts.Decorator) => {
return Maybe.lift(dec).bind(callExpression)
.bind(withIdentifier('Component'))
.fmap(() => this.readComponentMetadata(d, dec));
}));

let directiveMetadata = unwrapFirst(
(d.decorators || ([] as ts.Decorator[])).map((dec: ts.Decorator) =>
Maybe.lift(dec)
.bind(callExpression)
.bind(withIdentifier('Directive'))
.fmap(() => this.readDirectiveMetadata(d, dec))
));

return directiveMetadata || componentMetadata || undefined;
}

protected readDirectiveMetadata(d: ts.ClassDeclaration, dec: ts.Decorator): DirectiveMetadata {
const selector = this.getDecoratorArgument(dec)
.bind(expr => getStringInitializerFromProperty('selector', expr.properties))
.fmap(initializer => initializer.text);

return Object.assign(new DirectiveMetadata(), {
controller: d,
decorator: dec,
selector: selector.unwrap(),
});
}

protected readComponentMetadata(d: ts.ClassDeclaration, dec: ts.Decorator) {
const expr = this.getDecoratorArgument(dec);
const directiveMetadata = this.readDirectiveMetadata(d, dec);

const external_M = expr.fmap(() => this._urlResolver.resolve(dec));

const template_M: Maybe<TemplateMetadata> = external_M.bind(external =>
this.readComponentTemplateMetadata(dec, external));
const style_M: Maybe<StylesMetadata> = external_M.bind(external =>
this.readComponentStylesMetadata(dec, external));

return Object.assign(new ComponentMetadata(), directiveMetadata, {
template: template_M.unwrap(),
styles: style_M.unwrap(),
});
}

protected getDecoratorArgument(decorator: ts.Decorator): Maybe<ts.ObjectLiteralExpression> {
return decoratorArgument(decorator)
.bind(ifTrue(hasProperties));
}

protected readComponentTemplateMetadata(dec: ts.Decorator, external: MetadataUrls): Maybe<TemplateMetadata> {
// Resolve Inline template
return getTemplate(dec)
.fmap(inlineTemplate => ({
template: normalizeTransformed(Config.transformTemplate(inlineTemplate.text, null, dec)),
url: null,
node: inlineTemplate,
})
).catch(() => // If there's no valid inline template, we resolve external template
Maybe.lift(external.templateUrl)
.bind(url =>
this._resolve(url).fmap(template => ({
template: normalizeTransformed(Config.transformTemplate(template, url, dec)),
url,
node: null
}))
)
);
}

protected readComponentStylesMetadata(dec: ts.Decorator, external: MetadataUrls): Maybe<StylesMetadata> {
return getInlineStyle(dec).fmap(inlineStyles =>
// Resolve Inline styles
inlineStyles.elements.map((inlineStyle: ts.Expression) => {
if (isSimpleTemplateString(inlineStyle)) {
return {
style: normalizeTransformed(Config.transformStyle(inlineStyle.text, null, dec)),
url: null,
node: inlineStyle as ts.Node,
};
}
}).filter(v => !!v)
).catch(() => // If there's no valid inline styles, we resolve external styles
Maybe.lift(external.styleUrls)
.fmap(urls => urls.map(url => // Resolve each style URL and transform to metadata
this._resolve(url).fmap(style => ({
style: normalizeTransformed(Config.transformStyle(style, url, dec)),
url,
node: null,
}))
))
// merge Maybe<StyleMetadata>[] to Maybe<StyleMetadata[]>
.bind(url_Ms => listToMaybe<StyleMetadata>(url_Ms))
);
}

private _resolve(url: string): Maybe<string> {
try {
return Maybe.lift(this._fileResolver.resolve(url));
} catch (e) {
logger.info('Cannot read file' + url);
return Maybe.nothing;
}

readComponentStylesMetadata(dec: ts.Decorator, external: MetadataUrls) {
let styles: any[];
const inlineStyles_M = getInlineStyle(dec)
.fmap(inlineStyles => {
return inlineStyles.elements.map((inlineStyle: ts.Expression) => {
if (isSimpleTemplateString(inlineStyle)) {
return {
style: normalizeTransformed(Config.transformStyle(inlineStyle.text, null, dec)),
url: null,
node: inlineStyle,
};
}
}).filter(v => !!v);
});

if (inlineStyles_M.isSomething) {
return inlineStyles_M.unwrap();
} else if (external.styleUrls) {
// TODO: Refactoring this requires adding seem to fileResolver
try {
styles = <any>external.styleUrls.map((url: string) => {
const style = this._fileResolver.resolve(url);
const transformed = normalizeTransformed(Config.transformStyle(style, url, dec));
return {
style: transformed, url,
node: null
};
});
} catch (e) {
logger.info('Unable to read external style. ' + e.toString());
}
}
return styles;
}

readComponentMetadata(d: ts.ClassDeclaration, dec: ts.Decorator) {
const expr = this.getDecoratorArgument(dec);
const directiveMetadata = this.readDirectiveMetadata(d, dec);

const external_M = expr.fmap(() => this._urlResolver.resolve(dec));

const template_M = external_M.fmap(
(external) => this.readComponentTemplateMetadata(dec, external));
const style_M = external_M.fmap(
(external) => this.readComponentStylesMetadata(dec, external));

return Object.assign(new ComponentMetadata(), directiveMetadata, {
template: template_M.unwrap(),
styles: style_M.unwrap(),
});
}

protected getDecoratorArgument(decorator: ts.Decorator): Maybe<ts.ObjectLiteralExpression> {
return decoratorArgument(decorator)
.bind(ifTrue(hasProperties));
}
}
}

0 comments on commit 373b152

Please sign in to comment.