diff --git a/packages/@glimmer/app-compiler/README.md b/packages/@glimmer/app-compiler/README.md new file mode 100644 index 000000000..438c223b8 --- /dev/null +++ b/packages/@glimmer/app-compiler/README.md @@ -0,0 +1,72 @@ +# @glimmer/app-compiler + +A broccoli plugin that wraps Glimmer's optimizing compiler for producing the required pre-computed objects for Glimmer VM based applications. + +## Basic Usage + +For most apps the plugin can be used as the following: + +```ts +import { BundleCompiler } from '@glimmer/app-compiler'; +... + +let optimizedApp = BundleCompiler(app, { + projectPath: 'my-app', + mode: 'module-unification' +}); + +return optimizedApp; +``` + +## Advanced Usage + +If you need to do more advanced things like registering AST plugins or using custom project layout you can do something like the following: + +```ts +import { BundleCompiler } from '@glimmer/app-compiler'; +import { BundleCompilerDelegate } from '@glimmer/compiler-delegates' +... + +class MyCustomCompilerDelegate implements BundleCompilerDelegate { + ... +} + +let optimizedApp = BundleCompiler(app, { + projectPath: 'my-app', + delegate: MyCustomCompilerDelegate, + outputFiles: { + heapFile: 'snowflake/location/template.gbx', + dataSegment: 'snowflake/data.js' + }, + bundleCompiler: { + plugins: [MyASTPlugin] + } +}); + +return optimizedApp; +``` + +### Options + +```ts +interface GlimmerBundleCompilerOptions { + projectPath: string; // where the project is at + bundleCompiler: BundleCompilerOptions; // Options specifically for the compiler + outputFiles?: OutputFiles; // Where to write the output + delegate?: BundleCompilerDelegateConstructor; // Delegate to discover information about templates + mode?: 'module-unification'; // Builtin delegate +} + +interface BundleCompilerDelegateConstructor { + new(): BundleCompilerDelegate; +} + +export interface OutputFiles { + dataSegment: Option; + heapFile: Option; +} + +interface BundleCompilerOptions { + plugins?: ASTPluginBuilder[]; +} +``` diff --git a/packages/@glimmer/app-compiler/index.ts b/packages/@glimmer/app-compiler/index.ts new file mode 100644 index 000000000..1e854326e --- /dev/null +++ b/packages/@glimmer/app-compiler/index.ts @@ -0,0 +1 @@ +export { default as GlimmerBundleCompiler } from './src/bundle-compiler'; diff --git a/packages/@glimmer/app-compiler/package.json b/packages/@glimmer/app-compiler/package.json new file mode 100644 index 000000000..a3f61f9f5 --- /dev/null +++ b/packages/@glimmer/app-compiler/package.json @@ -0,0 +1,28 @@ +{ + "name": "@glimmer/app-compiler", + "version": "0.8.0-alpha.9", + "description": "Broccoli tooling for Glimmer-VM based applications", + "repository": "https://github.com/glimmerjs/glimmer.js", + "license": "MIT", + "files": [ + "dist" + ], + "main": "dist/commonjs/es5/index.js", + "module": "dist/modules/es2017/index.js", + "types": "dist/types/index.d.ts", + "dependencies": { + "@glimmer/application": "0.8.0-alpha.10", + "@glimmer/bundle-compiler": "^0.29.8", + "@glimmer/compiler-delegates": "0.8.0-alpha.9", + "@glimmer/interfaces": "^0.29.8", + "@glimmer/opcode-compiler": "^0.29.8", + "broccoli-plugin": "^1.3.0", + "debug": "^3.1.0", + "walk-sync": "^0.3.2" + }, + "devDependencies": { + "broccoli-stew": "^1.5.0", + "broccoli-test-helper": "^1.2.0", + "co": "^4.6.0" + } +} diff --git a/packages/@glimmer/app-compiler/src/bundle-compiler.ts b/packages/@glimmer/app-compiler/src/bundle-compiler.ts new file mode 100644 index 000000000..f5fda384d --- /dev/null +++ b/packages/@glimmer/app-compiler/src/bundle-compiler.ts @@ -0,0 +1,111 @@ +import { BundleCompiler, BundleCompilerOptions, specifierFor } from '@glimmer/bundle-compiler'; +import { ModuleUnificationCompilerDelegate, BundleCompilerDelegate, OutputFiles } from '@glimmer/compiler-delegates'; +import Plugin from 'broccoli-plugin'; +import walkSync from 'walk-sync'; +import { readFileSync, writeFileSync, mkdirSync } from 'fs'; +import { join, extname } from 'path'; +import { mainLayout } from '@glimmer/application'; +import { CompilableTemplate } from '@glimmer/opcode-compiler'; + +export type CompilerMode = 'module-unification'; + +export interface BundleCompilerDelegateConstructor { + new(projectPath: string, outputFiles: OutputFiles): BundleCompilerDelegate; +} + +export interface GlimmerBundleCompilerOptions { + projectPath: string; + bundleCompiler: BundleCompilerOptions; + outputFiles?: OutputFiles; + delegate?: BundleCompilerDelegateConstructor; + mode?: CompilerMode; +} + +export default class GlimmerBundleCompiler extends Plugin { + options: GlimmerBundleCompilerOptions; + inputPaths: string[]; + outputPath: string; + compiler: BundleCompiler; + private delegate: BundleCompilerDelegate; + constructor(inputNode, options) { + super([inputNode], options); + this.options = this.defaultOptions(options); + } + + private defaultOptions(options: GlimmerBundleCompilerOptions) { + if (!options.projectPath) { + throw new Error('Must supply a projectPath'); + } + + if (!options.mode && !options.delegate) { + throw new Error('Must pass a bundle compiler mode or pass a custom compiler delegate.'); + } + + return Object.assign({ + outputFiles: { + heapFile: 'src/templates.gbx', + dataSegment: 'src/data-segment.js' + } + }, options); + } + + listEntries() { + let [srcPath] = this.inputPaths; + return walkSync.entries(srcPath); + } + + _readFile(file) { + return readFileSync(join(this.inputPaths[0], file), 'UTF-8'); + } + + createBundleCompiler() { + let delegate; + let { options } = this; + if (options.mode && options.mode === 'module-unification') { + delegate = this.delegate = new ModuleUnificationCompilerDelegate(options.projectPath, options.outputFiles); + } else if (options.delegate) { + delegate = this.delegate = new options.delegate(options.projectPath, options.outputFiles); + } + + this.compiler = new BundleCompiler(delegate, options.bundleCompiler = {}); + } + + build() { + if (!this.compiler && !this.delegate) { + this.createBundleCompiler(); + } + + let { outputPath } = this; + + let specifier = specifierFor('__BUILTIN__', 'default'); + let compilable = CompilableTemplate.topLevel(JSON.parse(mainLayout.block), this.compiler.compileOptions(specifier)); + + this.compiler.addCustom(specifier, compilable); + + this.listEntries().forEach(entry => { + let { relativePath } = entry; + if (entry.isDirectory()) { + mkdirSync(join(outputPath, relativePath)); + } else { + let content = this._readFile(relativePath); + if (extname(relativePath) === '.hbs') { + let normalizedPath = this.delegate.normalizePath(relativePath); + let specifier = this.delegate.specifierFor(normalizedPath); + this.compiler.add(specifier, content); + } else { + writeFileSync(join(outputPath, relativePath), content); + } + } + }); + + let { heap, pool } = this.compiler.compile(); + let map = this.compiler.getSpecifierMap(); + let { compiledBlocks } = this.compiler; + let dataSegment = this.delegate.generateDataSegment(map, pool, heap.table, heap.handle, compiledBlocks); + + let { outputFiles } = this.options; + + writeFileSync(join(outputPath, outputFiles.dataSegment), dataSegment); + writeFileSync(join(outputPath, outputFiles.heapFile), new Buffer(heap.buffer)); + } +} diff --git a/packages/@glimmer/app-compiler/test/node/bundle-compiler-test.ts b/packages/@glimmer/app-compiler/test/node/bundle-compiler-test.ts new file mode 100644 index 000000000..f39d6ee32 --- /dev/null +++ b/packages/@glimmer/app-compiler/test/node/bundle-compiler-test.ts @@ -0,0 +1,134 @@ +import { module, test } from 'qunitjs'; +import { GlimmerBundleCompiler } from '@glimmer/app-compiler'; +import { createTempDir, buildOutput } from 'broccoli-test-helper'; +import co from 'co'; +import { ModuleUnificationCompilerDelegate } from '@glimmer/compiler-delegates'; + +class TestModuleUnificationDelegate extends ModuleUnificationCompilerDelegate { + normalizePath(modulePath: string): string { + return modulePath.replace('my-app/', ''); + } +} + +module('Broccol Glimmer Bundle Compiler', function(hooks) { + let input = null; + + hooks.beforeEach(() => createTempDir().then(tempDir => (input = tempDir))); + + hooks.afterEach(() => { + input.dispose(); + }); + + test('requires a mode or delegate', function (assert) { + assert.throws(() => { + new GlimmerBundleCompiler(input.path(), { projectPath: 'src' }); + }, /Must pass a bundle compiler mode or pass a custom compiler delegate\./); + }); + + test('requires a project path', function (assert) { + assert.throws(() => { + new GlimmerBundleCompiler(input.path(), { + mode: 'module-unification' + }); + }, /Must supply a projectPath/); + }); + + test('syncs forward all files', co.wrap(function *(assert) { + input.write({ + 'my-app': { + 'package.json': JSON.stringify({name: 'my-app'}), + src: { + ui: { + components: { + A: { + 'template.hbs': '
Hello
', + 'component.ts': 'export default class A {}' + }, + + B: { + 'template.hbs': 'From B: {{@bar}}', + 'component.ts': 'export default class B {}' + }, + + C: { + 'template.hbs': 'From C', + 'component.ts': 'export default class C {}' + }, + + D: { + 'template.hbs': '{{component C}}', + 'component.ts': 'export default class D {}' + } + } + } + } + } + }); + + let compiler = new GlimmerBundleCompiler(input.path(), { + projectPath: `${input.path()}/my-app`, + delegate: TestModuleUnificationDelegate, + outputFiles: { + dataSegment: 'my-app/src/data.js', + heapFile: 'my-app/src/templates.gbx' + } + }); + + let output = yield buildOutput(compiler); + let files = output.read(); + + assert.deepEqual(Object.keys(files), ['my-app']); + assert.deepEqual(Object.keys(files['my-app']).sort(), ['src', 'package.json'].sort()); + assert.deepEqual(Object.keys(files['my-app'].src).sort(), ['ui', 'templates.gbx', 'data.js'].sort()); + assert.deepEqual(Object.keys(files['my-app'].src.ui), ['components']); + + Object.keys(files['my-app'].src.ui.components).forEach((component) => { + assert.deepEqual(Object.keys(files['my-app'].src.ui.components[component]), ['component.ts']); + }); + })); + + test('[MU] compiles the gbx and data segment', co.wrap(function *(assert) { + input.write({ + 'my-app': { + 'package.json': JSON.stringify({name: 'my-app'}), + src: { + ui: { + components: { + A: { + 'template.hbs': '
Hello
' + }, + + B: { + 'template.hbs': 'From B:
{{@bar}}' + }, + + C: { + 'template.hbs': 'From C' + }, + + D: { + 'template.hbs': '{{component C}}' + } + } + } + } + } + }); + + let compiler = new GlimmerBundleCompiler(input.path(), { + projectPath: `${input.path()}/my-app`, + delegate: TestModuleUnificationDelegate, + outputFiles: { + dataSegment: 'my-app/src/data.js', + heapFile: 'my-app/src/templates.gbx' + } + }); + + let output = yield buildOutput(compiler); + let files = output.read(); + + let buffer = new Uint16Array(files['my-app'].src['templates.gbx']); + + assert.ok(buffer, 'Buffer is aligned'); + })); +}); diff --git a/packages/@glimmer/application/index.ts b/packages/@glimmer/application/index.ts index d13e78084..cb3f5ed7d 100644 --- a/packages/@glimmer/application/index.ts +++ b/packages/@glimmer/application/index.ts @@ -4,3 +4,4 @@ export { default as ApplicationRegistry } from './src/application-registry'; export { RuntimeResolver } from './src/runtime-resolver'; export { default as Iterable } from './src/iterable'; export { debugInfoForReference } from './src/helpers/action'; +export { default as mainLayout } from './src/templates/main'; diff --git a/packages/@glimmer/compiler-delegates/index.ts b/packages/@glimmer/compiler-delegates/index.ts index e9e207df0..b3fd5e79d 100644 --- a/packages/@glimmer/compiler-delegates/index.ts +++ b/packages/@glimmer/compiler-delegates/index.ts @@ -1 +1,3 @@ export { default as ModuleUnificationCompilerDelegate } from './src/delegates/module-unification'; +export { BundleCompilerDelegate } from './src/bundle'; +export { OutputFiles } from './src/utils/code-gen'; diff --git a/packages/@glimmer/compiler-delegates/package.json b/packages/@glimmer/compiler-delegates/package.json index b17e9884e..036e33537 100644 --- a/packages/@glimmer/compiler-delegates/package.json +++ b/packages/@glimmer/compiler-delegates/package.json @@ -11,13 +11,15 @@ "module": "dist/modules/es2017/index.js", "types": "dist/types/index.d.ts", "dependencies": { - "debug": "^3.1.0", "@glimmer/bundle-compiler": "^0.29.8", + "@glimmer/component": "^0.8.0", + "@glimmer/interfaces": "^0.29.8", "@glimmer/opcode-compiler": "^0.29.8", + "@glimmer/program": "^0.29.8", "@glimmer/syntax": "^0.29.8", "@glimmer/util": "^0.29.8", - "@glimmer/program": "^0.29.8", - "@glimmer/interfaces": "^0.29.8", + "@types/node": "^8.0.46", + "debug": "^3.1.0", "glimmer-analyzer": "^0.3.2", "resolve": "^1.4.0" } diff --git a/packages/@glimmer/compiler-delegates/src/bundle.ts b/packages/@glimmer/compiler-delegates/src/bundle.ts index fcbb43bf7..7f7c4f779 100644 --- a/packages/@glimmer/compiler-delegates/src/bundle.ts +++ b/packages/@glimmer/compiler-delegates/src/bundle.ts @@ -1,8 +1,15 @@ -import { CompilerDelegate, SpecifierMap } from '@glimmer/bundle-compiler'; +import { CompilerDelegate, SpecifierMap, Specifier } from '@glimmer/bundle-compiler'; import { ConstantPool } from '@glimmer/program'; +import { SerializedTemplateBlock } from '@glimmer/wire-format'; +import { ICompilableTemplate } from '@glimmer/opcode-compiler'; +import { ProgramSymbolTable } from '@glimmer/interfaces'; export type Metadata = {}; +export type AddedTemplate = SerializedTemplateBlock | ICompilableTemplate; + export interface BundleCompilerDelegate extends CompilerDelegate { - generateDataSegment(map: SpecifierMap, pool: ConstantPool, heapTable: number[]): string; + normalizePath(absolutePath: string): string; + specifierFor(relativePath: string): Specifier; + generateDataSegment(map: SpecifierMap, pool: ConstantPool, heapTable: number[], nextFreeHandle: number, blocks: Map): string; } diff --git a/packages/@glimmer/compiler-delegates/src/capabilities.ts b/packages/@glimmer/compiler-delegates/src/capabilities.ts deleted file mode 100644 index c0757da7a..000000000 --- a/packages/@glimmer/compiler-delegates/src/capabilities.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const CAPABILITIES = { - dynamicLayout: false, - prepareArgs: false, - elementHook: true, - staticDefinitions: false, - dynamicTag: true, - createArgs: true, - attributeHook: true -}; diff --git a/packages/@glimmer/compiler-delegates/src/delegates/module-unification.ts b/packages/@glimmer/compiler-delegates/src/delegates/module-unification.ts new file mode 100644 index 000000000..770e8e0a4 --- /dev/null +++ b/packages/@glimmer/compiler-delegates/src/delegates/module-unification.ts @@ -0,0 +1,256 @@ +import { BundleCompilerDelegate } from '../bundle'; +import { getImportStatements, OutputFiles } from '../utils/code-gen'; +import { BundleCompiler, Specifier, specifierFor, SpecifierMap } from '@glimmer/bundle-compiler'; +import { SymbolTable, ProgramSymbolTable, ComponentCapabilities } from '@glimmer/interfaces'; +import { expect, Dict } from '@glimmer/util'; +import { relative } from 'path'; +import { SerializedTemplateBlock } from '@glimmer/wire-format'; +import { CompilableTemplate, CompileOptions, ICompilableTemplate } from '@glimmer/opcode-compiler'; +import { ConstantPool } from '@glimmer/program'; +import Debug from 'debug'; +import { Project } from 'glimmer-analyzer'; +import { CAPABILITIES } from '@glimmer/component'; + +const debug = Debug('@glimmer/compiler-delegates:mu-delegate'); + +const BUILTINS = ['action', 'if']; + +export default class ModuleUnificationCompilerDelegate implements BundleCompilerDelegate { + public bundleCompiler: BundleCompiler; + protected project: Project; + protected specifiersToSymbolTable: Map = new Map(); + + constructor(protected projectPath: string, public outputFiles: OutputFiles) { + debug('initialized MU compiler delegate; project=%s', projectPath); + this.project = new Project(projectPath); + } + + hasComponentInScope(name: string, referrer: Specifier) { + debug('hasComponentInScope; name=%s; referrer=%o', name, referrer); + + let referrerSpec = expect( + this.project.specifierForPath(referrer.module), + `The component <${name}> was used in ${referrer.module} but could not be found.` + ); + + return !!this.project.resolver.identify(`template:${name}`, referrerSpec); + } + + resolveComponentSpecifier(name: string, referrer: Specifier) { + let referrerSpec = expect(this.project.specifierForPath(referrer.module), `expected specifier for path ${referrer.module}`); + let resolved = this.project.resolver.identify(`template:${name}`, referrerSpec); + + let resolvedSpecifier = this.getCompilerSpecifier(resolved); + return resolvedSpecifier; + } + + specifierFor(relativePath: string) { + return specifierFor(relativePath, 'default'); + } + + /** + * Converts a path relative to the current working directory into a path + * relative to the project root. + */ + normalizePath(modulePath: string): string { + let project = this.project; + let projectPath = relative(process.cwd(), project.projectDir); + + return relative(projectPath, modulePath); + } + + protected getCompilerSpecifier(specifier: string): Specifier { + let modulePath = expect(this.project.pathForSpecifier(specifier), `couldn't find module with specifier '${specifier}'`); + + return specifierFor(modulePath, 'default'); + } + + getComponentCapabilities(): ComponentCapabilities { + return CAPABILITIES; + } + + hasHelperInScope(helperName: string, referrer: Specifier) { + if (BUILTINS.indexOf(helperName) > -1) { return true; } + + let referrerSpec = this.project.specifierForPath(referrer.module) || undefined; + return !!this.project.resolver.identify(`helper:${helperName}`, referrerSpec); + } + + resolveHelperSpecifier(helperName: string, referrer: Specifier) { + if (BUILTINS.indexOf(helperName) > -1) { + return specifierFor('__BUILTIN__', helperName); + } + + let referrerSpec = this.project.specifierForPath(referrer.module) || undefined; + let resolvedSpec = this.project.resolver.identify(`helper:${helperName}`, referrerSpec); + + return this.getCompilerSpecifier(resolvedSpec); + } + + getComponentLayout(_specifier: Specifier, block: SerializedTemplateBlock, options: CompileOptions): ICompilableTemplate { + return CompilableTemplate.topLevel(block, options); + } + + generateDataSegment(map: SpecifierMap, pool: ConstantPool, table: number[]) { + debug('generating data segment'); + + let externalModuleTable = this.generateExternalModuleTable(map); + let constantPool = this.generateConstantPool(pool); + let heapTable = this.generateHeapTable(table); + let specifierMap = this.generateSpecifierMap(map); + let symbolTables = this.generateSymbolTables(); + + let source = strip` + ${externalModuleTable} + ${heapTable} + ${constantPool} + ${specifierMap} + ${symbolTables} + export default { moduleTable, heapTable, pool, specifierMap, symbolTables };`; + debug('generated data segment; source=%s', source); + + return source; + } + + generateSymbolTables() { + let symbolTables: Dict = {}; + + for (let [specifier, table] of this.specifiersToSymbolTable) { + let muSpecifier = this.muSpecifierForSpecifier(specifier); + symbolTables[muSpecifier] = table; + } + + return `const symbolTables = ${inlineJSON(symbolTables)};`; + } + + generateSpecifierMap(map: SpecifierMap) { + let entries = Array.from(map.vmHandleBySpecifier.entries()); + let specifierMap: Dict = {}; + + for (let [specifier, handle] of entries) { + let muSpecifier = this.muSpecifierForSpecifier(specifier); + + specifierMap[muSpecifier] = handle; + } + + return `const specifierMap = ${inlineJSON(specifierMap)};`; + } + + muSpecifierForSpecifier(specifier: Specifier): string { + let { module } = specifier; + let project = this.project; + + if (module === '__BUILTIN__') { + return module; + } + + return expect( + project.specifierForPath(specifier.module), + `expected to have a MU specifier for module ${specifier.module}` + ); + } + + generateHeapTable(table: number[]) { + return strip` + const heapTable = ${inlineJSON(table)}; + `; + } + + generateConstantPool(pool: ConstantPool) { + return strip` + const pool = ${inlineJSON(pool)}; + `; + } + + generateExternalModuleTable(map: SpecifierMap) { + let project = this.project; + let self = this; + + // First, convert the map into an array of specifiers, using the handle + // as the index. + let modules = toSparseArray(map.byHandle) + .map(normalizeModulePaths) + .filter(m => m) as Specifier[]; + + let source = generateExternalModuleTable(modules); + + return source; + + function normalizeModulePaths(moduleSpecifier: Specifier) { + let specifier = self.muSpecifierForSpecifier(moduleSpecifier); + + debug('resolved MU specifier; specifier=%s', specifier); + + let [type] = specifier.split(':'); + + switch (type) { + case 'template': + return getComponentImport(specifier); + case 'helper': + return moduleSpecifier; + case '__BUILTIN__': + return null; + default: + throw new Error(`Unsupported type in specifier map: ${type}`); + } + } + + function getComponentImport(referrer: string): Specifier | null { + let componentSpec = project.resolver.identify('component:', referrer); + if (componentSpec) { + let componentPath = project.pathForSpecifier(componentSpec)!; + debug('found corresponding component; referrer=%s; path=%s', referrer, componentPath); + return specifierFor(componentPath, 'default'); + } + + debug('no component for template; referrer=%s', referrer); + return null; + } + } + + hasModifierInScope(_modifierName: string, _referrer: Specifier): boolean { + return false; + } + resolveModifierSpecifier(_modifierName: string, _referrer: Specifier): Specifier { + throw new Error("Method not implemented."); + } + hasPartialInScope(_partialName: string, _referrer: Specifier): boolean { + return false; + } + resolvePartialSpecifier(_partialName: string, _referrer: Specifier): Specifier { + throw new Error("Method not implemented."); + } +} + +function inlineJSON(data: any) { + return `JSON.parse(${JSON.stringify(JSON.stringify(data))})`; +} + +function toSparseArray(map: Map): T[] { + let array: T[] = []; + + for (let [key, value] of map) { + array[key] = value; + } + + return array; +} + +function generateExternalModuleTable(modules: Specifier[]) { + let { imports, identifiers } = getImportStatements(modules); + + return ` +${imports.join('\n')} +const moduleTable = [${identifiers.join(',')}]; +`; +} + +function strip(strings: TemplateStringsArray, ...args: string[]) { + if (typeof strings === 'object') { + return strings.map((str: string, i: number) => { + return `${str.split('\n').map(s => s.trim()).join('')}${args[i] ? args[i] : ''}`; + }).join(''); + } else { + return strings[0].split('\n').map((s: string) => s.trim()).join(' '); + } +} diff --git a/packages/@glimmer/compiler-delegates/src/utils/code-gen.ts b/packages/@glimmer/compiler-delegates/src/utils/code-gen.ts index 3e1d3e854..3db16420d 100644 --- a/packages/@glimmer/compiler-delegates/src/utils/code-gen.ts +++ b/packages/@glimmer/compiler-delegates/src/utils/code-gen.ts @@ -1,5 +1,11 @@ import { Specifier } from "@glimmer/bundle-compiler"; import { dict, Dict } from "@glimmer/util"; +import { Option } from "@glimmer/interfaces"; + +export interface OutputFiles { + dataSegment: Option; + heapFile: Option; +} /** * Generates a valid JavaScript identifier for a module path. Can optionally take diff --git a/packages/@glimmer/component/index.ts b/packages/@glimmer/component/index.ts index 551a5390e..5ee51bf13 100644 --- a/packages/@glimmer/component/index.ts +++ b/packages/@glimmer/component/index.ts @@ -5,3 +5,4 @@ export { tracked, setPropertyDidChange, tagForProperty, UntrackedPropertyError } export { RootReference, CachedReference, UpdatableReference, ConditionalReference } from './src/references'; export { default as TemplateMeta } from './src/template-meta'; export { default as Bounds } from './src/bounds'; +export { CAPABILITIES } from './src/capabilities'; diff --git a/packages/@glimmer/component/src/capabilities.ts b/packages/@glimmer/component/src/capabilities.ts new file mode 100644 index 000000000..901669d09 --- /dev/null +++ b/packages/@glimmer/component/src/capabilities.ts @@ -0,0 +1,10 @@ +import { ComponentCapabilities } from "@glimmer/interfaces"; + +export const CAPABILITIES: ComponentCapabilities = { + dynamicLayout: false, + dynamicTag: true, + prepareArgs: false, + createArgs: true, + attributeHook: true, + elementHook: true +}; diff --git a/packages/@glimmer/component/src/component-definition.ts b/packages/@glimmer/component/src/component-definition.ts index 2a4c44633..485fe41ef 100644 --- a/packages/@glimmer/component/src/component-definition.ts +++ b/packages/@glimmer/component/src/component-definition.ts @@ -2,15 +2,7 @@ import ComponentManager from "./component-manager"; import { Option, ComponentCapabilities } from '@glimmer/interfaces'; import { ComponentFactory } from './component'; import { ComponentDefinition as IComponentDefinition } from '@glimmer/runtime'; - -const capabilities: ComponentCapabilities = { - dynamicLayout: false, - dynamicTag: true, - prepareArgs: false, - createArgs: true, - attributeHook: true, - elementHook: true -}; +import { CAPABILITIES as capabilities } from './capabilities'; export interface DefinitionState { /* Manager-related */ diff --git a/yarn.lock b/yarn.lock index 67fcd4217..a03d1aca4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,21 @@ # yarn lockfile v1 +"@glimmer/application@0.8.0-alpha.10": + version "0.8.0-alpha.10" + resolved "https://registry.yarnpkg.com/@glimmer/application/-/application-0.8.0-alpha.10.tgz#829a84e6d3e52af9fb4faed30f73f3a8c5847013" + dependencies: + "@glimmer/compiler" "^0.29.8" + "@glimmer/di" "^0.1.9" + "@glimmer/env" "^0.1.7" + "@glimmer/interfaces" "^0.29.8" + "@glimmer/object-reference" "^0.29.8" + "@glimmer/opcode-compiler" "^0.29.8" + "@glimmer/reference" "^0.29.8" + "@glimmer/resolver" "^0.3.0" + "@glimmer/runtime" "^0.29.8" + "@glimmer/util" "^0.29.8" + "@glimmer/build@^0.6.1", "@glimmer/build@^0.6.2": version "0.6.3" resolved "https://registry.yarnpkg.com/@glimmer/build/-/build-0.6.3.tgz#be259e08cb50da4f249a8e57e1cc7570029bd214" @@ -140,6 +155,14 @@ dependencies: "@glimmer/util" "^0.29.8" +"@glimmer/resolution-map-builder@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@glimmer/resolution-map-builder/-/resolution-map-builder-0.4.0.tgz#b999b51ea3046a44b323e7ef3683c22c99807ee3" + dependencies: + broccoli-plugin "^1.3.0" + silent-error "^1.0.1" + walk-sync "^0.3.1" + "@glimmer/resolver@^0.3.0": version "0.3.1" resolved "https://registry.yarnpkg.com/@glimmer/resolver/-/resolver-0.3.1.tgz#41069345b6f41beb0948cc35d8e4aa60adcadfc5" @@ -160,7 +183,7 @@ "@glimmer/vm" "^0.29.8" "@glimmer/wire-format" "^0.29.8" -"@glimmer/syntax@^0.29.8": +"@glimmer/syntax@^0.29.1", "@glimmer/syntax@^0.29.8": version "0.29.8" resolved "https://registry.yarnpkg.com/@glimmer/syntax/-/syntax-0.29.8.tgz#ada0e17d34fe0c8ce5b60f637e44c707f035d5ba" dependencies: @@ -205,6 +228,10 @@ dependencies: "@glimmer/util" "^0.29.8" +"@types/node@^8.0.46": + version "8.0.46" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.46.tgz#6e1766b2d0ed06631d5b5f87bb8e72c8dbb6888e" + "@types/qunit@^1.16.30": version "1.16.31" resolved "https://registry.yarnpkg.com/@types/qunit/-/qunit-1.16.31.tgz#169ba79df56f25f40556c39c544e018bb6390792" @@ -1700,7 +1727,7 @@ broccoli-source@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" -broccoli-stew@^1.1.1, broccoli-stew@^1.2.0, broccoli-stew@^1.3.3: +broccoli-stew@^1.1.1, broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.5.0.tgz#d7af8c18511dce510e49d308a62e5977f461883c" dependencies: @@ -1733,7 +1760,7 @@ broccoli-string-replace@^0.1.1: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" -broccoli-test-helper@^1.1.0: +broccoli-test-helper@^1.1.0, broccoli-test-helper@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/broccoli-test-helper/-/broccoli-test-helper-1.2.0.tgz#d01005d8611fd73ebe1b29552bf052ff59badfb4" dependencies: @@ -2435,7 +2462,7 @@ debug@2.3.3: dependencies: ms "0.7.2" -debug@^3.0.1: +debug@^3.0.1, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -3761,6 +3788,16 @@ git-repo-version@0.3.0: dependencies: git-repo-info "^1.0.4" +glimmer-analyzer@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/glimmer-analyzer/-/glimmer-analyzer-0.3.2.tgz#801f051db5943e529c60cb483c4f78e35623e395" + dependencies: + "@glimmer/resolution-map-builder" "^0.4.0" + "@glimmer/resolver" "^0.3.0" + "@glimmer/syntax" "^0.29.1" + debug "^3.1.0" + simple-html-tokenizer "^0.4.1" + glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"