├── .circleci └── config.yml ├── .gitattributes ├── .gitignore ├── .gitmodules ├── .npmignore ├── .travis.yml ├── .uglify.yml ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── assets ├── background.jpg └── logo.png ├── bower.json ├── examples ├── README.md ├── component-async.html ├── component.html ├── components │ ├── counter.mask │ ├── foo.mask │ └── panel.mask ├── import-async.html ├── import.html ├── interpolation.html ├── simple.html ├── statements.html └── syntax.html ├── package-lock.json ├── package.browser.yml ├── package.json ├── package.node.yml ├── projects ├── converter │ ├── src │ │ ├── Converter.ts │ │ ├── converters │ │ │ ├── DefineConverter.ts │ │ │ ├── EmbeddedModuleConverter.ts │ │ │ ├── Import.ts │ │ │ └── MethodConverter.ts │ │ └── utils │ │ │ └── interpolate.ts │ └── test │ │ └── converter.spec.ts ├── expression │ ├── src │ │ ├── ast.ts │ │ ├── astNode_utils.ts │ │ ├── ast_utils.ts │ │ ├── class │ │ │ ├── AwaitableCtx.ts │ │ │ ├── DeferStatement.ts │ │ │ ├── DeferredExp.ts │ │ │ ├── ISubscription.ts │ │ │ ├── ObjectStream.ts │ │ │ ├── PromisedStream.ts │ │ │ ├── SubjectKind.ts │ │ │ ├── SubjectStream.ts │ │ │ └── Subscription.ts │ │ ├── eval.ts │ │ ├── eval_async.ts │ │ ├── eval_deferred.ts │ │ ├── eval_statements.ts │ │ ├── exports.ts │ │ ├── parser.ts │ │ ├── scope-vars.ts │ │ ├── util.ts │ │ └── vars_helper.ts │ └── test │ │ ├── condition.spec.ts │ │ ├── eval.spec.ts │ │ ├── eval_observe.spec.ts │ │ ├── expressions-async.spec.ts │ │ ├── expressions-stream.spec.ts │ │ ├── expressions.spec.ts │ │ ├── serialize.spec.ts │ │ └── types.spec.ts ├── mask-binding │ ├── src │ │ ├── BindingProvider.ts │ │ ├── DomObjectTransport.ts │ │ ├── ValidatorProvider.ts │ │ ├── attributes │ │ │ ├── exports.ts │ │ │ ├── xClassToggle.ts │ │ │ ├── xToggle.ts │ │ │ └── xxVisible.ts │ │ ├── binders │ │ │ ├── EventEmitterBinder.ts │ │ │ ├── ExpressionBinder.ts │ │ │ ├── IBinder.ts │ │ │ ├── RxBinder.ts │ │ │ └── exports.ts │ │ ├── exports.ts │ │ ├── handlers │ │ │ ├── bind.ts │ │ │ ├── bind_node.ts │ │ │ ├── dualbind.ts │ │ │ ├── dualbind_node.ts │ │ │ ├── exports.ts │ │ │ ├── validate.ts │ │ │ ├── validate_group.ts │ │ │ └── visible.ts │ │ ├── sandbox │ │ │ └── CancelableAsync.ts │ │ ├── statements │ │ │ ├── base │ │ │ │ ├── ABoundStatement.ts │ │ │ │ └── ALoopBoundStatement.ts │ │ │ ├── exports.ts │ │ │ ├── if.ts │ │ │ ├── if_old.ts │ │ │ ├── listen.ts │ │ │ ├── loop │ │ │ │ ├── each.ts │ │ │ │ ├── each_old.ts │ │ │ │ ├── for.ts │ │ │ │ ├── for_old.ts │ │ │ │ └── utils.ts │ │ │ ├── switch.ts │ │ │ ├── utils.ts │ │ │ ├── visible.ts │ │ │ └── with.ts │ │ ├── utilities │ │ │ ├── bind.ts │ │ │ └── exports.ts │ │ └── utils │ │ │ ├── compo.ts │ │ │ ├── date.ts │ │ │ ├── dom.ts │ │ │ ├── exports.ts │ │ │ ├── expression.ts │ │ │ └── signal.ts │ └── test │ │ ├── bind.spec.ts │ │ ├── bind_compo_attr.spec.ts │ │ ├── bind_observe.spec.ts │ │ ├── dualbind.spec.ts │ │ ├── statements │ │ ├── each.spec.ts │ │ ├── for_in.spec.ts │ │ ├── for_of.spec.ts │ │ ├── for_of_observe.spec.ts │ │ ├── if.spec.ts │ │ ├── if_observe.spec.ts │ │ ├── listen.spec.ts │ │ ├── loop.spec.ts │ │ ├── switch.spec.ts │ │ ├── visible.spec.ts │ │ └── with.spec.ts │ │ ├── utils.ts │ │ └── validation.spec.ts ├── mask-compo │ ├── examples │ │ └── keyboard │ │ │ ├── events.html │ │ │ ├── hotkeys.html │ │ │ ├── signals.html │ │ │ └── signals_targets.html │ ├── src │ │ ├── DomLite.ts │ │ ├── compo │ │ │ ├── Compo.ts │ │ │ ├── CompoConfig.ts │ │ │ ├── CompoProto.ts │ │ │ ├── CompoStatics.ts │ │ │ ├── CompoStaticsGc.ts │ │ │ ├── Component.ts │ │ │ ├── EventsDeco.ts │ │ │ ├── anchor.ts │ │ │ ├── async.ts │ │ │ ├── children.ts │ │ │ ├── events.ts │ │ │ ├── find.ts │ │ │ └── pipes.ts │ │ ├── deco │ │ │ └── component_decorators.ts │ │ ├── exports.ts │ │ ├── handler │ │ │ └── slot.ts │ │ ├── jcompo │ │ │ └── jCompo.ts │ │ ├── keyboard │ │ │ ├── CombHandler.ts │ │ │ ├── Handler.ts │ │ │ ├── Hotkey.ts │ │ │ ├── IComb.ts │ │ │ ├── Key.ts │ │ │ ├── KeySequance.ts │ │ │ ├── const.ts │ │ │ ├── filters.ts │ │ │ └── utils.ts │ │ ├── model │ │ │ ├── IAttrDefinition.ts │ │ │ └── IComponent.ts │ │ ├── scope-vars.ts │ │ ├── signal │ │ │ ├── attributes.ts │ │ │ ├── compound.ts │ │ │ ├── exports.ts │ │ │ ├── toggle.ts │ │ │ └── utils.ts │ │ ├── touch │ │ │ ├── FastClick.ts │ │ │ ├── Handler.ts │ │ │ └── Touch.ts │ │ ├── tween │ │ │ ├── Tween.ts │ │ │ └── TweenManager.ts │ │ └── util │ │ │ ├── ani.ts │ │ │ ├── compo.ts │ │ │ ├── compo_ceateExt.ts │ │ │ ├── compo_create.ts │ │ │ ├── compo_inherit.ts │ │ │ ├── compo_meta.ts │ │ │ ├── dfr.ts │ │ │ ├── dom.ts │ │ │ ├── domLib.ts │ │ │ ├── event.ts │ │ │ ├── selector.ts │ │ │ ├── slots.ts │ │ │ └── traverse.ts │ └── test │ │ ├── attr.spec.ts │ │ ├── await.spec.ts │ │ ├── domLite.spec.ts │ │ ├── examples │ │ └── keyboard.spec.ts │ │ ├── inheritance.spec.ts │ │ ├── jquery.spec.ts │ │ ├── meta │ │ ├── attributes.spec.ts │ │ └── template.spec.ts │ │ ├── pipe.spec.ts │ │ ├── refs.spec.ts │ │ ├── signal.spec.ts │ │ ├── static.spec.ts │ │ └── tween.spec.ts ├── mask-j │ ├── src │ │ ├── jmask │ │ │ ├── jMask.ts │ │ │ ├── jmask.ts │ │ │ ├── manip_attr.ts │ │ │ ├── manip_class.ts │ │ │ ├── manip_dom.ts │ │ │ ├── proto.ts │ │ │ └── traverse.ts │ │ ├── scope-vars.ts │ │ └── util │ │ │ ├── array.ts │ │ │ ├── selector.ts │ │ │ └── utils.ts │ └── test │ │ ├── general.spec.ts │ │ └── selector.spec.ts ├── mask-node │ ├── examples │ │ ├── counter.js │ │ ├── define │ │ │ └── index.mask │ │ ├── import │ │ │ ├── counter.mask │ │ │ ├── doubleCounter.mask │ │ │ ├── heading.mask │ │ │ ├── index.html │ │ │ ├── index.mask │ │ │ └── subcounter.mask │ │ ├── index.js │ │ ├── index │ │ │ └── index.mask │ │ └── page │ │ │ ├── SimpleApp.mask │ │ │ ├── SimpleAppController.js │ │ │ └── simple.html │ ├── lib │ │ └── mask.bootstrap.js │ ├── src │ │ ├── bootstrap-wrapper.js │ │ ├── builder │ │ │ ├── build.js │ │ │ ├── build_component.js │ │ │ ├── ctx │ │ │ │ ├── CtxModels.ts │ │ │ │ └── CtxModules.ts │ │ │ ├── delegate │ │ │ │ ├── build_component.ts │ │ │ │ ├── builder_buildFactory.ts │ │ │ │ └── exports.ts │ │ │ └── dom │ │ │ │ └── build.ts │ │ ├── cache │ │ │ ├── CompoCacheCollection.ts │ │ │ ├── exports.ts │ │ │ └── utils.ts │ │ ├── client │ │ │ ├── bootstrap.ts │ │ │ ├── mock.ts │ │ │ ├── model.ts │ │ │ ├── setup-attr.ts │ │ │ ├── setup-compo.ts │ │ │ ├── setup-el.ts │ │ │ ├── setup-util.ts │ │ │ ├── setup.ts │ │ │ ├── traverse.ts │ │ │ ├── utils.ts │ │ │ └── vars.ts │ │ ├── const.ts │ │ ├── handlers │ │ │ └── document.ts │ │ ├── helper │ │ │ ├── Meta.ts │ │ │ ├── MetaParser.ts │ │ │ └── MetaSerializer.ts │ │ ├── html-dom │ │ │ ├── CommentNode.ts │ │ │ ├── ComponentNode.ts │ │ │ ├── DoctypeNodeInn.ts │ │ │ ├── DocumentFragmentInn.ts │ │ │ ├── DomB.ts │ │ │ ├── ElementNodeInn.ts │ │ │ ├── NodeBase.ts │ │ │ ├── ScriptElementInn.ts │ │ │ ├── StyleElementInn.ts │ │ │ ├── TextNodeInn.ts │ │ │ ├── UtilNodeInn.ts │ │ │ ├── documentInn.ts │ │ │ ├── exports.ts │ │ │ ├── jq │ │ │ │ ├── classList.ts │ │ │ │ ├── exports.ts │ │ │ │ ├── traverse.ts │ │ │ │ └── util │ │ │ │ │ └── selector.ts │ │ │ ├── tags.ts │ │ │ └── util │ │ │ │ ├── HtmlStream.ts │ │ │ │ ├── html.ts │ │ │ │ ├── node.ts │ │ │ │ ├── stringify.ts │ │ │ │ └── traverse.ts │ │ ├── html-page │ │ │ ├── exports.ts │ │ │ ├── scripts.ts │ │ │ └── transform.ts │ │ ├── mask.ts │ │ ├── mock │ │ │ ├── attr-handler.ts │ │ │ ├── mock.ts │ │ │ ├── tag-handler.ts │ │ │ └── util-handler.ts │ │ ├── node-wrapper.js │ │ ├── renderer │ │ │ └── exports.ts │ │ └── util │ │ │ ├── compo.ts │ │ │ ├── ctx.ts │ │ │ ├── json.ts │ │ │ ├── loaders.ts │ │ │ ├── meta.ts │ │ │ ├── node.ts │ │ │ └── path.ts │ └── test │ │ ├── config-d.js │ │ ├── config.js │ │ ├── dom │ │ ├── bootstrap │ │ │ └── client.spec.ts │ │ ├── component.spec.ts │ │ ├── feature │ │ │ ├── define.spec.ts │ │ │ ├── import.spec.ts │ │ │ └── style.spec.ts │ │ ├── statement │ │ │ ├── each.spec.ts │ │ │ ├── for.spec.ts │ │ │ ├── if.spec.ts │ │ │ ├── switch.spec.ts │ │ │ └── with.spec.ts │ │ ├── statement_bind │ │ │ ├── each.spec.ts │ │ │ ├── for.spec.ts │ │ │ ├── if.spec.ts │ │ │ ├── switch.spec.ts │ │ │ └── with.spec.ts │ │ └── utils.ts │ │ ├── examples │ │ ├── define.spec.ts │ │ ├── html.spec.ts │ │ └── import.spec.ts │ │ ├── node │ │ ├── attr │ │ │ ├── modes.spec.ts │ │ │ └── x.spec.ts │ │ ├── cache.spec.ts │ │ ├── content.spec.ts │ │ ├── feature │ │ │ ├── decorators.spec.ts │ │ │ ├── define.spec.ts │ │ │ └── import.spec.ts │ │ ├── helper.ts │ │ ├── modules │ │ │ ├── html.spec.ts │ │ │ └── imports.spec.ts │ │ ├── parser │ │ │ └── script.spec.ts │ │ ├── simple.spec.ts │ │ ├── statement │ │ │ ├── each.spec.ts │ │ │ ├── for_in.spec.ts │ │ │ ├── if.spec.ts │ │ │ └── switch.spec.ts │ │ ├── stringify.spec.ts │ │ ├── stringify_meta.spec.ts │ │ └── utils.js │ │ └── tmpl │ │ ├── a.mask │ │ ├── compos │ │ ├── bar.ts │ │ ├── clientAsyncCompo.ts │ │ ├── clientCompo.ts │ │ ├── foo.mask │ │ ├── foo.ts │ │ └── index.html │ │ └── import │ │ └── letters │ │ ├── a.mask │ │ ├── a_upper.mask │ │ ├── b.html │ │ └── letters.mask └── observer │ ├── src │ ├── Mutators.ts │ ├── exports.ts │ ├── expression.ts │ ├── expression_subscribe.ts │ ├── notify.ts │ ├── obj_crumbs.ts │ ├── obj_mutators.ts │ ├── obj_observe.ts │ ├── obj_props.ts │ ├── obj_stream.ts │ └── utils │ │ ├── expr.ts │ │ └── obj.ts │ └── test │ ├── expr.spec.ts │ ├── mutators.spec.ts │ ├── obj.spec.ts │ └── stream.spec.ts ├── src ├── api │ └── config.ts ├── arch │ └── Module.ts ├── autoreload │ ├── ModuleReload.ts │ ├── StateTree.ts │ ├── compo.ts │ ├── components.ts │ ├── element.ts │ └── wrapper.js ├── builder │ ├── BuilderData.ts │ ├── ctx.ts │ ├── delegate │ │ ├── IBuilderConfig.ts │ │ ├── build_component.ts │ │ ├── build_decorators.ts │ │ ├── build_many.ts │ │ ├── build_node.ts │ │ ├── build_textNode.ts │ │ ├── builder_buildFactory.ts │ │ └── exports.ts │ ├── dom │ │ └── build.ts │ ├── exports.ts │ ├── resume.ts │ ├── sandbox │ │ └── builder.iterate.js │ ├── svg │ │ └── build.ts │ └── util.ts ├── custom │ ├── IUtilType.ts │ ├── attribute.ts │ ├── exports.ts │ ├── mock-attributes.ts │ ├── mock-tags.ts │ ├── mock-utils.ts │ ├── optimize.ts │ ├── repositories.ts │ ├── statement.ts │ ├── tag.ts │ └── util.ts ├── dom │ ├── ComponentNode.ts │ ├── DecoratorNode.ts │ ├── Fragment.ts │ ├── INode.ts │ ├── Node.ts │ ├── NodeType.ts │ ├── TextNode.ts │ ├── dom.linked.js │ ├── exports.ts │ └── utils.ts ├── feature │ ├── Define.ts │ ├── Di.ts │ ├── TreeWalker.ts │ ├── decorators │ │ ├── decorators-desc.ts │ │ ├── decos │ │ │ └── singleton.ts │ │ ├── exports.ts │ │ ├── store.ts │ │ ├── utils.ts │ │ └── wrappers.ts │ ├── exports.ts │ ├── merge.ts │ ├── methods │ │ ├── IMethodNode.ts │ │ ├── define-methods.ts │ │ ├── exports.ts │ │ ├── handlers.ts │ │ ├── node-method.ts │ │ ├── parsers.ts │ │ ├── scope-refs.ts │ │ ├── source-url.ts │ │ └── utils.ts │ ├── modules │ │ ├── Import │ │ │ ├── Import.ts │ │ │ ├── ImportData.ts │ │ │ ├── ImportHtml.ts │ │ │ ├── ImportMask.ts │ │ │ ├── ImportScript.ts │ │ │ ├── ImportStyle.ts │ │ │ ├── ImportText.ts │ │ │ ├── ImportTypes.ts │ │ │ ├── exports.ts │ │ │ └── utils.ts │ │ ├── Module │ │ │ ├── Module.ts │ │ │ ├── ModuleData.ts │ │ │ ├── ModuleHtml.ts │ │ │ ├── ModuleMask.ts │ │ │ ├── ModuleScript.ts │ │ │ ├── ModuleStyle.ts │ │ │ ├── ModuleText.ts │ │ │ ├── ModuleTypes.ts │ │ │ ├── exports.ts │ │ │ ├── register.ts │ │ │ └── utils.ts │ │ ├── Opts.ts │ │ ├── await.ts │ │ ├── cache.ts │ │ ├── class │ │ │ └── Endpoint.ts │ │ ├── components.ts │ │ ├── config.ts │ │ ├── exports.ts │ │ ├── loaders.ts │ │ ├── tools │ │ │ ├── build.ts │ │ │ └── dependencies.ts │ │ ├── types.ts │ │ ├── utils.ts │ │ └── utils │ │ │ └── mask-module.ts │ ├── optimize.ts │ └── run.ts ├── handlers │ ├── content.ts │ ├── debug.ts │ ├── define.ts │ ├── exports.ts │ ├── html.ts │ ├── svg.ts │ ├── template.ts │ └── var.ts ├── mask.ts ├── parser │ ├── ParserAst.ts │ ├── Templates.ts │ ├── config.ts │ ├── const.ts │ ├── cursor.ts │ ├── exports.ts │ ├── html │ │ ├── html_entities.js │ │ └── parser.ts │ ├── interpolation.ts │ ├── mask │ │ ├── parser.ts │ │ ├── partials │ │ │ ├── attributes.ts │ │ │ └── literal.ts │ │ └── stringify.ts │ ├── object │ │ ├── ObjectLexer.ts │ │ ├── compile.ts │ │ ├── consume.ts │ │ └── tokens.ts │ ├── parsers │ │ ├── IImportNode.ts │ │ ├── content.ts │ │ ├── content │ │ │ └── style.ts │ │ ├── define.ts │ │ ├── import.ts │ │ └── var.ts │ └── utils.ts ├── renderer │ └── exports.ts ├── scope-vars.ts ├── statements │ ├── each.ts │ ├── exports.ts │ ├── for.ts │ ├── if.ts │ ├── repeat.ts │ ├── switch.ts │ ├── utils.ts │ ├── visible.ts │ └── with.ts ├── types │ ├── Parameters.ts │ └── types-ts.ts ├── umd-wrapper.js └── util │ ├── array.ts │ ├── attr.ts │ ├── compo.ts │ ├── css.ts │ ├── dom.ts │ ├── env_class.ts │ ├── exports.ts │ ├── listeners.ts │ ├── object.ts │ ├── path.ts │ ├── reporters.ts │ └── resource │ ├── file.ts │ └── transports │ ├── json.ts │ ├── script_browser.ts │ ├── script_node.ts │ ├── style_browser.ts │ ├── style_node.ts │ ├── xhr_base.ts │ ├── xhr_browser.ts │ └── xhr_node.ts ├── test ├── benchmark │ ├── bower.json │ ├── bower_components │ │ ├── maskjs-0.12.23 │ │ │ ├── .bower.json │ │ │ ├── README.md │ │ │ ├── bower.json │ │ │ ├── lib │ │ │ │ ├── formatter.js │ │ │ │ ├── html_entities.js │ │ │ │ ├── mask.bootstrap.js │ │ │ │ ├── mask.js │ │ │ │ ├── mask.min.js │ │ │ │ ├── mask.min.js.map │ │ │ │ ├── mask.node.js │ │ │ │ └── plugin.reload.js │ │ │ └── package.json │ │ └── maskjs-0.52.4 │ │ │ ├── .bower.json │ │ │ ├── README.md │ │ │ ├── bower.json │ │ │ ├── lib │ │ │ ├── html_entities.js │ │ │ ├── mask.bootstrap.js │ │ │ ├── mask.js │ │ │ ├── mask.min.js │ │ │ ├── mask.min.js.map │ │ │ ├── mask.node.js │ │ │ └── plugin.reload.js │ │ │ └── package.json │ ├── define.test │ ├── eval.test │ └── render.test ├── config.js ├── dom │ ├── api │ │ └── register.spec.ts │ ├── async.spec.ts │ ├── feature │ │ ├── TreeWalker.spec.ts │ │ ├── decorators.spec.ts │ │ ├── define-methods.spec.ts │ │ ├── define.spec.ts │ │ ├── di.spec.ts │ │ ├── merge.spec.ts │ │ ├── methods-define.spec.ts │ │ └── optimize.spec.ts │ ├── handler │ │ ├── await.spec.ts │ │ ├── debug.spec.ts │ │ └── include.spec.ts │ ├── interpolations.spec.ts │ ├── lexer │ │ └── object.spec.ts │ ├── modules │ │ ├── async.spec.ts │ │ ├── build.spec.ts │ │ ├── custom.spec.ts │ │ ├── import.spec.ts │ │ ├── js-compo.spec.ts │ │ ├── npm.spec.ts │ │ ├── ns.spec.ts │ │ └── prefixes.spec.ts │ ├── node │ │ ├── define.spec.ts │ │ ├── function.spec.ts │ │ ├── pipe.spec.ts │ │ ├── properties.spec.ts │ │ ├── script.spec.ts │ │ ├── slot_event.spec.ts │ │ ├── style.spec.ts │ │ └── var.spec.ts │ ├── parse-errors.spec.ts │ ├── parse.spec.ts │ ├── parsers │ │ ├── html.spec.ts │ │ └── var.spec.ts │ ├── render.spec.ts │ ├── statements-obs.spec.ts │ ├── statements.spec.ts │ ├── svg │ │ └── render.spec.ts │ ├── utils.spec.ts │ └── utils.ts ├── examples │ ├── component-async.spec.ts │ ├── generic.spec.ts │ ├── import.spec.ts │ └── simple.spec.ts ├── node │ ├── comments.spec.ts │ ├── feature │ │ └── merge.spec.ts │ ├── interpolation.spec.ts │ ├── parser │ │ ├── decorators.spec.ts │ │ ├── define.spec.ts │ │ ├── html.spec.ts │ │ ├── import.spec.ts │ │ ├── method.spec.ts │ │ ├── mixed.spec.ts │ │ ├── object-lex.spec.ts │ │ ├── props.spec.ts │ │ └── script.spec.ts │ ├── stringify-nodes.spec.ts │ ├── stringify.spec.ts │ └── utils │ │ ├── path.spec.ts │ │ └── path.ts └── tmpl │ ├── a.mask │ ├── modules │ ├── ImmediateInvokeDefine.mask │ ├── baz.ini │ ├── baz.txt │ ├── data_baz.json │ ├── data_foo.js │ ├── data_foo_1.js │ ├── data_foo_2.js │ ├── data_foo_3.js │ ├── data_service.js │ ├── defines.mask │ ├── defines_scopes.mask │ ├── ext-less │ │ ├── myinfo │ │ ├── mymeta │ │ └── view │ ├── h4.mask │ ├── header_content.mask │ ├── html │ │ └── header.html │ ├── model.mask │ ├── nest-a.mask │ ├── nest-b.mask │ ├── nest.mask │ ├── package.mask │ ├── route_resolver.mask │ ├── static.mask │ ├── style.css │ └── versioned.mask │ ├── npm │ ├── foo-none.mask │ ├── foo.mask │ └── node_modules │ │ └── foo-module │ │ ├── index.mask │ │ └── package.json │ └── stringify │ ├── content.mask │ ├── content.min.mask │ ├── html.mask │ ├── interpolation.mask │ ├── literals.mask │ ├── literals.min.mask │ ├── misc.mask │ ├── misc.min.mask │ ├── node_head.mask │ ├── node_head.min.mask │ ├── node_many.mask │ ├── node_many.min.mask │ ├── node_single.mask │ └── node_single.min.mask ├── tools └── build-dts.ts ├── tsconfig-build-node.json ├── tsconfig-build.json ├── tsconfig.json ├── types ├── index.d.ts └── mask.d.ts ├── typings.json └── typings ├── globals ├── assertion │ ├── index.d.ts │ └── typings.json └── atma-utest │ ├── index.d.ts │ └── typings.json └── index.d.ts /.gitattributes: -------------------------------------------------------------------------------- 1 | *.test linguist-language=JavaScript -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # build 2 | /lib/* 3 | /ts-temp 4 | 5 | # node 6 | node_modules 7 | !test/tmpl/npm/node_modules 8 | 9 | # WebStorm 10 | .idea -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ref-utils"] 2 | path = ref-utils 3 | url = https://github.com/atmajs/utils 4 | [submodule "wiki"] 5 | path = wiki 6 | url = https://github.com/atmajs/MaskJS.wiki.git 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # ide 2 | .komodotools 3 | *.komodoproject 4 | 5 | .gitignore 6 | .gitmodules 7 | .gitattributes 8 | .npmignore 9 | .vscode 10 | .travis.yml 11 | 12 | build.js 13 | node_modules/ 14 | tools/ 15 | test/ 16 | src/ 17 | builds/ 18 | examples/ 19 | ts-temp/ 20 | /ref-** 21 | /projects 22 | 23 | 24 | tsconfig-build.json -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | cache: 4 | npm: false 5 | 6 | services: 7 | - xvfb 8 | 9 | # prevent travis from recursive gitsubmodule checkout 10 | git: 11 | submodules: false 12 | 13 | addons: 14 | firefox: "latest" 15 | 16 | before_script: 17 | - git submodule update --init 18 | - export DISPLAY=:99.0 19 | - sleep 5 20 | - npm run build 21 | - sleep 8 22 | - npm run server & 23 | - sleep 8 24 | - firefox http://localhost:5777/utest/ & 25 | - sleep 8 26 | 27 | script: 28 | - "npm test" 29 | 30 | language: node_js 31 | 32 | node_js: 33 | - 16 34 | -------------------------------------------------------------------------------- /.uglify.yml: -------------------------------------------------------------------------------- 1 | 2 | warnings: true 3 | compress: 4 | dead_code: true 5 | unused: true 6 | arguments: false 7 | booleans: false 8 | collapse_vars: false 9 | comparisons: false 10 | conditionals: false 11 | hoist_funs: false 12 | hoist_props: false 13 | hoist_vars: false 14 | if_return: false 15 | inline: false 16 | join_vars: false 17 | keep_fnames: true 18 | loops: false 19 | negate_iife: false 20 | reduce_funcs: false 21 | reduce_vars: false 22 | switches: false 23 | typeofs: false 24 | properties: false 25 | sequences: false 26 | side_effects: false 27 | drop_debugger: false 28 | global_defs: 29 | DEBUG: false 30 | mangle: false 31 | parse: {} 32 | output: 33 | beautify: true 34 | braces: true 35 | quote_style: 1 36 | indent_level: 2 37 | comments: "^!" 38 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules\\typescript\\lib" 3 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright 2017, Atma.js 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /assets/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atmajs/MaskJS/f3951546aa9b5ada57fe66a35e7fa4809108f6c2/assets/background.jpg -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atmajs/MaskJS/f3951546aa9b5ada57fe66a35e7fa4809108f6c2/assets/logo.png -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "maskjs", 3 | "version": "0.73.3", 4 | "homepage": "https://github.com/atmajs/MaskJS", 5 | "authors": [ 6 | "Alex Kit " 7 | ], 8 | "description": "Template / Markup / HMVC Engine", 9 | "main": "lib/mask.js", 10 | "keywords": [ 11 | "MVC", 12 | "Components" 13 | ], 14 | "license": "MIT", 15 | "ignore": [ 16 | ".travis.yml", 17 | "build.js", 18 | "*.komodoproject", 19 | "builds/", 20 | "src/", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ] 26 | } -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | #### Start the local server 2 | 3 | ```bash 4 | npm install 5 | npm run examples 6 | ``` 7 | 8 | #### Navigate to an example 9 | 10 | ```bash 11 | http://localhost:5777/examples/simple.html 12 | ``` -------------------------------------------------------------------------------- /examples/component-async.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /examples/components/counter.mask: -------------------------------------------------------------------------------- 1 | import panel as layout from './panel'; 2 | 3 | define counter { 4 | var index = 0; 5 | 6 | slot increment () { 7 | this.scope.index++; 8 | } 9 | 10 | layout { 11 | @title > 'Counter Panel' 12 | @body { 13 | button x-tap='increment' > 'Increment' 14 | span { 15 | ' (Current) ' 16 | tt > i > '~[bind: index ]' 17 | } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /examples/components/foo.mask: -------------------------------------------------------------------------------- 1 | import panel as Panel from './panel'; 2 | 3 | define foo extends Panel { 4 | @title > 'Foo title' 5 | @body { 6 | i > tt > 'Content' 7 | } 8 | } -------------------------------------------------------------------------------- /examples/components/panel.mask: -------------------------------------------------------------------------------- 1 | define panel as (div.panel) { 2 | 3 | // controllers scope 4 | var collapsed = false; 5 | 6 | // controllers slot 7 | slot collapse () { 8 | this.scope.collapsed = !this.scope.collapsed; 9 | } 10 | 11 | // style for the panels DIV 12 | style scoped { 13 | :host { 14 | width: 80%; 15 | margin: auto; 16 | padding: 20px; 17 | box-shadow: 1px 1px 5px #333; 18 | } 19 | h4 { 20 | background: steelblue; 21 | color: white; 22 | padding: 10px; 23 | cursor: pointer; 24 | -webkit-user-select: none; 25 | } 26 | small { 27 | color: #ccc; 28 | } 29 | } 30 | 31 | h4 x-tap=collapse { 32 | small > 'Click to toggle ' 33 | @title; 34 | } 35 | 36 | +visible (collapsed !== true) > section .body { 37 | @body; 38 | } 39 | } -------------------------------------------------------------------------------- /examples/import-async.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/import.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /examples/simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 10 |
11 | 12 | 13 | 27 | 28 | -------------------------------------------------------------------------------- /examples/syntax.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 60 | 61 | 62 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /projects/converter/src/converters/EmbeddedModuleConverter.ts: -------------------------------------------------------------------------------- 1 | import { INode } from '@core/dom/INode'; 2 | 3 | export const EmbeddedModuleConverter = { 4 | convert (node: INode, stream?) { 5 | var path = u_resolvePath(x.attr.path, null, null, this), 6 | type = node.attr.contentType, 7 | endpoint = new Endpoint(path, type); 8 | 9 | m_registerModule(x.nodes, endpoint); 10 | 11 | } 12 | } -------------------------------------------------------------------------------- /projects/converter/src/converters/Import.ts: -------------------------------------------------------------------------------- 1 | import { IImportNode } from '@core/parser/parsers/IImportNode'; 2 | import { interpolate } from '../utils/interpolate'; 3 | import { u_resolvePathFromImport } from '@core/feature/modules/utils'; 4 | 5 | export const ImportConverter = { 6 | convert (node: IImportNode, stream) { 7 | 8 | let imports = node.exports.map(exp => { 9 | let name = exp.name; 10 | if (exp.alias) { 11 | name += ': ' + exp.alias 12 | } 13 | return name; 14 | }).join(', '); 15 | 16 | let path = u_resolvePathFromImport(node); 17 | 18 | return interpolate(Template.Import, { 19 | imports, 20 | path 21 | }) 22 | } 23 | } 24 | 25 | const Template = { 26 | Import: ` 27 | 28 | import { %imports% } from '%path%'; 29 | ` 30 | } -------------------------------------------------------------------------------- /projects/converter/src/converters/MethodConverter.ts: -------------------------------------------------------------------------------- 1 | import { IMethodNode } from '@core/feature/methods/IMethodNode'; 2 | import { interpolate } from '../utils/interpolate'; 3 | 4 | export const MethodConverter = { 5 | convert (node: IMethodNode, target: 'func' | 'method' = 'func') { 6 | let name = node.name, 7 | args = node.args && node.args.map(x => x.prop).join(', '), 8 | body = node.body, 9 | prefix = []; 10 | 11 | if (node.flagAsync) { 12 | prefix.push('async'); 13 | } 14 | 15 | return interpolate(Template[target], { 16 | prefix: prefix.join(' '), 17 | name, 18 | args, 19 | body 20 | }); 21 | } 22 | } 23 | 24 | const Template = { 25 | func: ` 26 | %prefix% function %name% (%args%) { 27 | %body% 28 | } 29 | `, 30 | method: ` 31 | %prefix% %name% (%args%) { 32 | %body% 33 | } 34 | ` 35 | } 36 | -------------------------------------------------------------------------------- /projects/converter/src/utils/interpolate.ts: -------------------------------------------------------------------------------- 1 | import { obj_getProperty } from '@utils/obj'; 2 | 3 | export function interpolate (template, model) { 4 | 5 | template = template.replace(/%([\w\.\d]+)%/g, (full, property) => { 6 | return obj_getProperty(model, property); 7 | }); 8 | 9 | return template; 10 | } -------------------------------------------------------------------------------- /projects/converter/test/converter.spec.ts: -------------------------------------------------------------------------------- 1 | import { Converter } from '../src/Converter'; 2 | 3 | UTest({ 4 | 'should convert defines to scripts' () { 5 | let template = ` 6 | import Bar from '../Bar'; 7 | 8 | define Foo { 9 | div > 'foo' 10 | function async onRenderStart (model, ctx) { 11 | this.model = 1; 12 | } 13 | } 14 | `; 15 | let output = ` 16 | import { Bar } from '../Bar.mask'; 17 | 18 | class Foo extends mask.Component { 19 | template = \`div > 'foo'\` 20 | async onRenderStart (model, ctx) { 21 | this.model = 1; 22 | } 23 | } 24 | mask.define('Foo', Foo); 25 | export { Foo } 26 | `; 27 | 28 | let script = Converter.convert(template); 29 | 30 | let _output = clean(output); 31 | let _script = clean(script); 32 | console.log('_'); 33 | console.log('>', _output); 34 | console.log('>', _script); 35 | console.log('_'); 36 | eq_(_output, _script); 37 | } 38 | }); 39 | 40 | 41 | function clean (str: string) { 42 | return str.replace(/[\s\n]/g, ''); 43 | } -------------------------------------------------------------------------------- /projects/expression/src/astNode_utils.ts: -------------------------------------------------------------------------------- 1 | import { _evaluateAst } from './eval'; 2 | 3 | export const Ast_FunctionRefUtil = { 4 | evalArguments: function (node, model, ctx, ctr, preResults) { 5 | var args = node.arguments, 6 | out = [], 7 | i = -1, 8 | imax = args.length; 9 | while ( ++i < imax ) { 10 | out[i] = _evaluateAst(args[i], model, ctx, ctr, preResults); 11 | } 12 | return out; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /projects/expression/src/class/ISubscription.ts: -------------------------------------------------------------------------------- 1 | export interface ISubscription { 2 | unsubscribe (cb?) 3 | } 4 | -------------------------------------------------------------------------------- /projects/expression/src/class/PromisedStream.ts: -------------------------------------------------------------------------------- 1 | import { SubjectKind } from './SubjectKind'; 2 | import { SubjectStream } from './SubjectStream'; 3 | export class PromisedStream extends SubjectStream { 4 | resolve(x: T) { 5 | this.next(x); 6 | } 7 | reject(err: Error | any) { 8 | this.error(err); 9 | } 10 | then(onSuccess, onError?) { 11 | if (this._error !== void 0) { 12 | onError?.(this._error); 13 | return; 14 | } 15 | if (this.value !== void 0) { 16 | onSuccess?.(this.value); 17 | return; 18 | } 19 | let opts = this.kind === SubjectKind.Stream 20 | ? null 21 | : OPTS_ONCE; 22 | this._cbs.push([onSuccess, onError, opts]); 23 | if (this._pipe != null && this._cbs.length === 1) { 24 | if ('subscribe' in this._pipe) { 25 | this._pipe.subscribe(this.next, this.error); 26 | return; 27 | } 28 | if ('then' in this._pipe) { 29 | (this._pipe as any).then(this.next, this.error); 30 | return; 31 | } 32 | } 33 | } 34 | } 35 | 36 | const OPTS_ONCE = { once: true }; 37 | -------------------------------------------------------------------------------- /projects/expression/src/class/SubjectKind.ts: -------------------------------------------------------------------------------- 1 | export enum SubjectKind { 2 | Value, 3 | Stream, 4 | Promise 5 | } 6 | -------------------------------------------------------------------------------- /projects/expression/src/class/Subscription.ts: -------------------------------------------------------------------------------- 1 | import { SubjectStream } from './SubjectStream'; 2 | export class Subscription { 3 | constructor(public stream: SubjectStream, public cb: Function) {} 4 | unsubscribe(cb?) { 5 | this.stream.unsubscribe(this.cb ?? cb); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/expression/src/eval_statements.ts: -------------------------------------------------------------------------------- 1 | import { _parse } from './parser'; 2 | import { Ast_Body, Ast_Statement } from './ast'; 3 | import { _evaluateAst } from './eval'; 4 | 5 | export function _evaluateStatements(expr, model?, ctx?, ctr?, node?){ 6 | 7 | var body = _parse(expr, false, node).body, 8 | args = [], 9 | imax = body.length, 10 | i = -1 11 | ; 12 | var group = new Ast_Body; 13 | while( ++i < imax ){ 14 | group.body.push(body[i]); 15 | if ((body[i] as Ast_Statement).join != null) { 16 | continue; 17 | } 18 | 19 | args.push(_evaluateAst(group, model, ctx, ctr)); 20 | group.body.length = 0; 21 | } 22 | return args; 23 | } 24 | -------------------------------------------------------------------------------- /projects/expression/test/serialize.spec.ts: -------------------------------------------------------------------------------- 1 | import { expression_parse } from '@project/expression/src/exports'; 2 | 3 | UTest({ 4 | 'should serialize function call with arguments' () { 5 | let expr = 'this.foo(bar)'; 6 | let ast = expression_parse(expr); 7 | let str = ast.toString(); 8 | eq_(str, expr); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /projects/expression/test/types.spec.ts: -------------------------------------------------------------------------------- 1 | import { expression_eval } from '../src/exports'; 2 | 3 | UTest({ 4 | $config: { 5 | breakOnError: true 6 | }, 7 | 'supports bigint literals' () { 8 | eq_( 9 | expression_eval('1n + 2n'), 10 | 3n 11 | ); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /projects/mask-binding/src/attributes/exports.ts: -------------------------------------------------------------------------------- 1 | import './xxVisible' 2 | import './xToggle' 3 | import './xClassToggle' -------------------------------------------------------------------------------- /projects/mask-binding/src/attributes/xClassToggle.ts: -------------------------------------------------------------------------------- 1 | import { customAttr_register } from '@core/custom/exports'; 2 | import { domLib, Component } from '@compo/exports'; 3 | 4 | /** 5 | * Toggle Class Name 6 | * 7 | * button x-toggle='click: selected' 8 | */ 9 | 10 | customAttr_register('x-class-toggle', 'client', function(node, attrVal, model, ctx, element){ 11 | 12 | var event = attrVal.substring(0, attrVal.indexOf(':')), 13 | klass = attrVal.substring(event.length + 1).trim(); 14 | 15 | 16 | Component.Dom.addEventListener(element, event, function(){ 17 | domLib(element).toggleClass(klass); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /projects/mask-binding/src/attributes/xToggle.ts: -------------------------------------------------------------------------------- 1 | import { customAttr_register } from '@core/custom/exports'; 2 | import { expression_eval_safe } from '../utils/expression'; 3 | import { obj_setProperty } from '@utils/obj'; 4 | import { expression_varRefs } from '@project/expression/src/exports'; 5 | import { Component } from '@compo/exports'; 6 | 7 | /** 8 | * Toggle value with ternary operator on an event. 9 | * 10 | * button x-toggle='click: foo === "bar" ? "zet" : "bar" > 'Toggle' 11 | */ 12 | customAttr_register('x-toggle', 'client', function(node, attrValue, model, ctx, el, ctr){ 13 | var event = attrValue.substring(0, attrValue.indexOf(':')), 14 | expression = attrValue.substring(event.length + 1), 15 | ref = expression_varRefs(expression); 16 | 17 | if (typeof ref !== 'string') { 18 | // assume is an array 19 | ref = ref[0]; 20 | } 21 | 22 | Component.Dom.addEventListener(el, event, function(){ 23 | var val = expression_eval_safe(expression, model, ctx, ctr, node); 24 | obj_setProperty(model, ref, val); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /projects/mask-binding/src/attributes/xxVisible.ts: -------------------------------------------------------------------------------- 1 | 2 | import { customAttr_register } from '@core/custom/exports'; 3 | import { expression_eval } from '@project/expression/src/exports'; 4 | import { Component } from '@compo/exports'; 5 | import { expression_createBinder, expression_bind, expression_unbind } from '@project/observer/src/exports'; 6 | 7 | customAttr_register('xx-visible', function(node, attrValue, model, ctx, el, ctr) { 8 | 9 | var binder = expression_createBinder(attrValue, model, ctx, ctr, function(value){ 10 | el.style.display = value ? '' : 'none'; 11 | }); 12 | 13 | expression_bind(attrValue, model, ctx, ctr, binder); 14 | 15 | Component.attach(ctr, 'dispose', function(){ 16 | expression_unbind(attrValue, model, ctr, binder); 17 | }); 18 | 19 | if (expression_eval(attrValue, model, ctx, ctr, node)) { 20 | el.style.display = 'none'; 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /projects/mask-binding/src/binders/EventEmitterBinder.ts: -------------------------------------------------------------------------------- 1 | import { class_create } from '@utils/class'; 2 | import { log_error } from '@core/util/reporters'; 3 | import { IBinder } from './IBinder'; 4 | import { expression_evalStatements } from '@project/expression/src/exports'; 5 | 6 | /* 7 | * "expression, ...args" 8 | * expression: to get the IEventEmitter 9 | */ 10 | export const EventEmitterBinder = class_create(IBinder, { 11 | on: function(exp, model, ctx, ctr, cb){ 12 | call('on', exp, model, ctr, cb); 13 | }, 14 | off: function(exp, model, ctr, cb){ 15 | call('off', exp, model, ctr, cb); 16 | }, 17 | }); 18 | 19 | function call (method, expr, model, ctr, cb) { 20 | var arr = expression_evalStatements(expr, model, null, ctr); 21 | var observable = arr.shift(); 22 | if (observable == null || observable[method] == null) { 23 | log_error('Method is undefined on observable: ' + method); 24 | return; 25 | } 26 | arr.push(cb); 27 | observable[method].apply(observable, arr); 28 | } 29 | -------------------------------------------------------------------------------- /projects/mask-binding/src/binders/ExpressionBinder.ts: -------------------------------------------------------------------------------- 1 | import { IBinder } from './IBinder'; 2 | import { expression_bind, expression_unbind } from '@project/observer/src/exports'; 3 | import { class_create } from '@utils/class'; 4 | 5 | export const ExpressionBinder = class_create(IBinder, { 6 | on: expression_bind, 7 | off: expression_unbind 8 | }); 9 | -------------------------------------------------------------------------------- /projects/mask-binding/src/binders/IBinder.ts: -------------------------------------------------------------------------------- 1 | import { class_create } from '@utils/class'; 2 | 3 | export const IBinder = class_create({ 4 | constructor: function (exp, model, ctr) { 5 | this.exp = exp; 6 | this.ctr = ctr; 7 | this.model = model; 8 | this.cb = null; 9 | }, 10 | on: null, 11 | bind: function(this: any, cb){ 12 | this.cb = cb; 13 | // we have here no access to the ctx, so pass null 14 | this.on(this.exp, this.model, null, this.ctr, cb); 15 | }, 16 | dispose: function(){ 17 | this.off(this.exp, this.model, this.ctr, this.cb); 18 | this.exp = this.model = this.ctr = this.cb = null; 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /projects/mask-binding/src/binders/RxBinder.ts: -------------------------------------------------------------------------------- 1 | import { IBinder } from './IBinder'; 2 | import { error_withCompo } from '@core/util/reporters'; 3 | import { class_create } from '@utils/class'; 4 | import { expression_evalStatements } from '@project/expression/src/exports'; 5 | 6 | /* 7 | * "expression, ...args" 8 | * expression: to get the RxObservable {subscribe:IDisposable} 9 | */ 10 | 11 | export const RxBinder = class_create(IBinder, { 12 | stream: null, 13 | on: function call (expr, model, ctr, cb) { 14 | var arr = expression_evalStatements(expr, model, null, ctr); 15 | 16 | var stream = arr.shift(); 17 | if (stream == null || stream.subscribe == null) { 18 | error_withCompo('Subscribe method is undefined on RxObservable', ctr); 19 | return; 20 | } 21 | arr.push(cb); 22 | this.stream = stream.subscribe.apply(stream, arr); 23 | }, 24 | off: function(){ 25 | if (this.stream == null) { 26 | return; 27 | } 28 | this.stream.dispose(); 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /projects/mask-binding/src/binders/exports.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitterBinder } from './EventEmitterBinder'; 2 | import { ExpressionBinder } from './ExpressionBinder'; 3 | import { RxBinder } from './RxBinder'; 4 | 5 | export var Binders = { 6 | EventEmitterBinder: EventEmitterBinder, 7 | ExpressionBinder: ExpressionBinder, 8 | RxBinder: RxBinder 9 | }; 10 | -------------------------------------------------------------------------------- /projects/mask-binding/src/exports.ts: -------------------------------------------------------------------------------- 1 | import './attributes/exports' 2 | import './handlers/exports' 3 | import './statements/exports' 4 | import './utilities/exports' 5 | 6 | import { CustomProviders } from './BindingProvider'; 7 | 8 | export { Validators, registerValidator } from './ValidatorProvider'; 9 | export { obj_addObserver, obj_removeObserver } from '@project/observer/src/exports' 10 | 11 | 12 | export const BindingProviders = CustomProviders; 13 | 14 | export function registerBinding (name, Prov) { 15 | CustomProviders[name] = Prov; 16 | } 17 | -------------------------------------------------------------------------------- /projects/mask-binding/src/handlers/bind.ts: -------------------------------------------------------------------------------- 1 | import { BindingProvider } from '../BindingProvider'; 2 | import { customTag_register } from '@core/custom/exports'; 3 | 4 | 5 | /** 6 | * Mask Custom Tag Handler 7 | * attr = 8 | * attr: {String} - attribute name to bind 9 | * prop: {Stirng} - property name to bind 10 | * - : {default} - innerHTML 11 | */ 12 | 13 | 14 | 15 | (function() { 16 | 17 | function Bind() {} 18 | 19 | customTag_register(':bind', Bind); 20 | customTag_register( 'bind', Bind); 21 | 22 | Bind.prototype = { 23 | constructor: Bind, 24 | renderEnd: function(els, model, cntx, container){ 25 | 26 | this.provider = BindingProvider.create(model, container, this, 'single'); 27 | 28 | BindingProvider.bind(this.provider); 29 | }, 30 | dispose: function(){ 31 | if (this.provider && typeof this.provider.dispose === 'function') { 32 | this.provider.dispose(); 33 | } 34 | } 35 | }; 36 | 37 | 38 | }()); 39 | -------------------------------------------------------------------------------- /projects/mask-binding/src/handlers/bind_node.ts: -------------------------------------------------------------------------------- 1 | import { customTag_register } from '@core/custom/exports'; 2 | import { BindingProvider } from '@binding/BindingProvider'; 3 | 4 | (function() { 5 | 6 | function Bind() {} 7 | 8 | customTag_register(':bind', Bind); 9 | customTag_register( 'bind', Bind); 10 | 11 | Bind.prototype = { 12 | constructor: Bind, 13 | renderStart: function(model, ctx, container){ 14 | 15 | this.provider = BindingProvider.create(model, container, this, 'single'); 16 | this.provider.objectChanged(); 17 | } 18 | }; 19 | 20 | 21 | }()); 22 | -------------------------------------------------------------------------------- /projects/mask-binding/src/handlers/exports.ts: -------------------------------------------------------------------------------- 1 | import './visible' 2 | import './validate' 3 | import './validate_group' 4 | 5 | //#if (NODE) 6 | import './bind_node' 7 | import './dualbind_node' 8 | //#endif 9 | 10 | //#if (BROWSER) 11 | import './bind' 12 | import './dualbind' 13 | //#endif -------------------------------------------------------------------------------- /projects/mask-binding/src/handlers/validate_group.ts: -------------------------------------------------------------------------------- 1 | import { customTag_register } from '@core/custom/exports'; 2 | 3 | function ValidateGroup() {} 4 | 5 | customTag_register(':validate:group', ValidateGroup); 6 | 7 | 8 | ValidateGroup.prototype = { 9 | constructor: ValidateGroup, 10 | validate: function() { 11 | var validations = getValidations(this); 12 | 13 | 14 | for (var i = 0, x, length = validations.length; i < length; i++) { 15 | x = validations[i]; 16 | if (!x.validate()) { 17 | return false; 18 | } 19 | } 20 | return true; 21 | } 22 | }; 23 | 24 | function getValidations(component, out = []){ 25 | 26 | if (component.components == null){ 27 | return out; 28 | } 29 | var compos = component.components; 30 | for(var i = 0, x, length = compos.length; i < length; i++){ 31 | x = compos[i]; 32 | 33 | if (x.compoName === 'validate'){ 34 | out.push(x); 35 | continue; 36 | } 37 | 38 | getValidations(x, out); 39 | } 40 | return out; 41 | } 42 | -------------------------------------------------------------------------------- /projects/mask-binding/src/handlers/visible.ts: -------------------------------------------------------------------------------- 1 | import { customTag_register } from '@core/custom/exports'; 2 | import { expression_eval } from '@project/expression/src/exports'; 3 | import { obj_addObserver } from '@project/observer/src/exports'; 4 | 5 | /** 6 | * visible handler. Used to bind directly to display:X/none 7 | * 8 | * attr = 9 | * check - expression to evaluate 10 | * bind - listen for a property change 11 | */ 12 | 13 | function VisibleHandler() {} 14 | 15 | customTag_register(':visible', VisibleHandler); 16 | 17 | 18 | VisibleHandler.prototype = { 19 | constructor: VisibleHandler, 20 | 21 | refresh: function(model, container) { 22 | container.style.display = expression_eval(this.attr.check, model) ? '' : 'none'; 23 | }, 24 | renderStart: function(model, cntx, container) { 25 | this.refresh(model, container); 26 | 27 | if (this.attr.bind) { 28 | obj_addObserver(model, this.attr.bind, this.refresh.bind(this, model, container)); 29 | } 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /projects/mask-binding/src/sandbox/CancelableAsync.ts: -------------------------------------------------------------------------------- 1 | import { class_create } from '@utils/class'; 2 | 3 | var CancelableAsync = class_create({ 4 | constructor: function(){ 5 | this.cbs = []; 6 | }, 7 | once: function(fn) { 8 | if (this.cbs == null) { 9 | return this.noop_; 10 | } 11 | var i = this.cbs.push(fn) - 1; 12 | return this.delegate_(i) ; 13 | }, 14 | cancel: function(){ 15 | this.cbs = null; 16 | }, 17 | invoke_: function(i, args){ 18 | var arr = this.cbs; 19 | if (arr == null) { 20 | return; 21 | } 22 | var fn = arr[i]; 23 | if (fn == null) { 24 | return; 25 | } 26 | arr[i] = null; 27 | fn.apply(null, args); 28 | }, 29 | delegate_: function(i){ 30 | var me = this; 31 | return function(){ 32 | me.invoke_(i, arguments); 33 | }; 34 | }, 35 | noop_: function(){ 36 | 37 | } 38 | }) 39 | -------------------------------------------------------------------------------- /projects/mask-binding/src/statements/exports.ts: -------------------------------------------------------------------------------- 1 | 2 | import './utils' 3 | import './if' 4 | import './loop/for' 5 | import './loop/each' 6 | import './switch' 7 | import './with' 8 | import './visible' 9 | import './listen' 10 | -------------------------------------------------------------------------------- /projects/mask-binding/src/utilities/exports.ts: -------------------------------------------------------------------------------- 1 | import './bind' -------------------------------------------------------------------------------- /projects/mask-binding/src/utils/date.ts: -------------------------------------------------------------------------------- 1 | 2 | export function date_ensure (val){ 3 | if (val == null || val === '') 4 | return null; 5 | 6 | var date = val; 7 | var type = typeof val; 8 | if (type === 'string') { 9 | date = new Date(val); 10 | 11 | if (rgx_es5Date.test(date) && val.indexOf('Z') === -1) { 12 | // adjust to local time (http://es5.github.io/x15.9.html#x15.9.1.15) 13 | val.setMinutes(val.getTimezoneOffset()); 14 | } 15 | } 16 | if (type === 'number') { 17 | date = new Date(val); 18 | } 19 | 20 | return isNaN(date) === false && typeof date.getFullYear === 'function' 21 | ? date 22 | : null 23 | ; 24 | }; 25 | 26 | var rgx_es5Date = /^\d{4}\-\d{2}/; 27 | -------------------------------------------------------------------------------- /projects/mask-binding/src/utils/dom.ts: -------------------------------------------------------------------------------- 1 | import { arr_each } from '@utils/arr'; 2 | 3 | export function dom_removeElement (el) { 4 | var parent = el.parentNode; 5 | if (parent == null) { 6 | return el; 7 | } 8 | return parent.removeChild(el); 9 | }; 10 | export function dom_removeAll (arr) { 11 | arr_each(arr, dom_removeElement); 12 | }; 13 | export function dom_hideEl (el){ 14 | if (el != null) { 15 | el.style.display = 'none'; 16 | } 17 | }; 18 | export function dom_hideAll (arr) { 19 | arr_each(arr, dom_hideEl); 20 | }; 21 | export function dom_showEl (el){ 22 | if (el != null) { 23 | el.style.display = ''; 24 | } 25 | }; 26 | export function dom_showAll (arr) { 27 | arr_each(arr, dom_showEl); 28 | }; 29 | export function dom_insertAfter (el, anchor) { 30 | return anchor.parentNode.insertBefore(el, anchor.nextSibling); 31 | }; 32 | export function dom_insertBefore (el, anchor) { 33 | return anchor.parentNode.insertBefore(el, anchor); 34 | }; 35 | -------------------------------------------------------------------------------- /projects/mask-binding/src/utils/exports.ts: -------------------------------------------------------------------------------- 1 | // import object 2 | // import object_observe 3 | // import date 4 | // import dom 5 | // import compo 6 | // import expression 7 | // import signal -------------------------------------------------------------------------------- /projects/mask-binding/src/utils/expression.ts: -------------------------------------------------------------------------------- 1 | import { expression_eval } from '@project/expression/src/exports' 2 | 3 | export function expression_eval_safe (expr, model, ctx, ctr, node?){ 4 | const x = expression_eval(expr, model, ctx, ctr, node); 5 | return x == null ? '' : x; 6 | }; 7 | -------------------------------------------------------------------------------- /projects/mask-binding/test/bind_compo_attr.spec.ts: -------------------------------------------------------------------------------- 1 | import { Mask as mask } from '@core/mask' 2 | 3 | UTest({ 4 | 'bind to attributes'() { 5 | mask.define('Foo', mask.Compo({ 6 | setAttribute: assert.await(function (name, val) { 7 | eq_(name, 'data-val', 'Foo'); 8 | }) 9 | })); 10 | 11 | var model = { 12 | foo: 'baz' 13 | }; 14 | var root = mask.Compo.initialize('Foo data-val="~[bind: foo]"', model); 15 | var Foo = root.find('Foo'); 16 | eq_(Foo.compoName, 'Foo'); 17 | eq_(Foo.attr['data-val'], 'baz'); 18 | model.foo = 'Foo'; 19 | }, 20 | 'bind to properties'() { 21 | mask.define('Foo', mask.Compo({ 22 | letter: 'a', 23 | template: ` 24 | div > '~[bind: this.letter]' 25 | ` 26 | })); 27 | 28 | var model = { 29 | modelLetter: 'c' 30 | }; 31 | var div = mask.render('Foo [letter] = "~[bind: modelLetter]"', model); 32 | eq_(div.textContent, 'c'); 33 | 34 | model.modelLetter = 'y'; 35 | eq_(div.textContent, 'y'); 36 | 37 | eq_($(div).compo().letter, 'y'); 38 | } 39 | }) 40 | -------------------------------------------------------------------------------- /projects/mask-compo/src/compo/Compo.ts: -------------------------------------------------------------------------------- 1 | import { obj_extend } from '@utils/obj'; 2 | import { _Array_slice } from '@utils/refs'; 3 | 4 | import { CompoProto } from './CompoProto'; 5 | import { CompoStatics } from './CompoStatics'; 6 | import { compo_createExt } from '../util/compo_ceateExt'; 7 | import { Component } from './Component'; 8 | 9 | export interface ICompo extends Component { 10 | (...args): new (...args) => Component 11 | new (...args): Component 12 | } 13 | 14 | export const Compo: ICompo & typeof CompoStatics = function (...args) { 15 | if (this instanceof Compo){ 16 | // used in Class({Base: Compo}) 17 | return void 0; 18 | } 19 | let Base = args.pop(); 20 | return compo_createExt(Base, args); 21 | }; 22 | 23 | Compo.prototype = CompoProto; 24 | obj_extend(Compo, CompoStatics); 25 | -------------------------------------------------------------------------------- /projects/mask-compo/src/compo/EventsDeco.ts: -------------------------------------------------------------------------------- 1 | const hasTouch = (function () { 2 | if (typeof document === 'undefined' || document == null) { 3 | return false; 4 | } 5 | if ('createTouch' in document) { 6 | return true; 7 | } 8 | try { 9 | return !!(document as any).createEvent('TouchEvent').initTouchEvent; 10 | } catch (error) { 11 | return false; 12 | } 13 | }()); 14 | 15 | export const EventsDeco = { 16 | 17 | 'touch' (type) { 18 | if (hasTouch === false) { 19 | return type; 20 | } 21 | 22 | if ('click' === type) { 23 | return 'touchend'; 24 | } 25 | 26 | if ('mousedown' === type) { 27 | return 'touchstart'; 28 | } 29 | 30 | if ('mouseup' === type) { 31 | return 'touchend'; 32 | } 33 | 34 | if ('mousemove' === type) { 35 | return 'touchmove'; 36 | } 37 | 38 | return type; 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /projects/mask-compo/src/compo/find.ts: -------------------------------------------------------------------------------- 1 | import { Dom } from '@core/dom/exports'; 2 | import { selector_parse } from '../util/selector'; 3 | import { find_findChild, find_findChildren, find_findSingle, find_findAll } from '../util/traverse'; 4 | 5 | export function compo_find (compo, selector: string): T{ 6 | return find_findSingle(compo, selector_parse(selector, Dom.CONTROLLER, 'down')); 7 | } 8 | export function compo_findAll (compo, selector: string): T[] { 9 | return find_findAll(compo, selector_parse(selector, Dom.CONTROLLER, 'down')); 10 | } 11 | export function compo_closest (compo, selector: string): T { 12 | return find_findSingle(compo, selector_parse(selector, Dom.CONTROLLER, 'up')); 13 | } 14 | export function compo_children (compo, selector: string): T[]{ 15 | return find_findChildren(compo, selector_parse(selector, Dom.CONTROLLER)); 16 | } 17 | export function compo_child (compo, selector): T { 18 | return find_findChild(compo, selector_parse(selector, Dom.CONTROLLER)); 19 | } -------------------------------------------------------------------------------- /projects/mask-compo/src/exports.ts: -------------------------------------------------------------------------------- 1 | export { CompoProto } from './compo/CompoProto' 2 | export { Component } from './compo/Component' 3 | export { Compo } from './compo/Compo' 4 | export { domLib } from './scope-vars' -------------------------------------------------------------------------------- /projects/mask-compo/src/handler/slot.ts: -------------------------------------------------------------------------------- 1 | import { _global } from '@utils/refs' 2 | import { customTag_register } from '@core/custom/exports'; 3 | import { expression_eval } from '@project/expression/src/exports'; 4 | 5 | function SlotHandler() {} 6 | 7 | customTag_register(':slot', SlotHandler); 8 | 9 | SlotHandler.prototype = { 10 | constructor: SlotHandler, 11 | renderEnd: function(element, model, cntx, container){ 12 | this.slots = {}; 13 | 14 | this.expression = this.attr.on; 15 | 16 | this.slots[this.attr.signal] = this.handle; 17 | }, 18 | handle: function(){ 19 | var expr = this.expression; 20 | 21 | expression_eval(expr, this.model, _global, this); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /projects/mask-compo/src/keyboard/Hotkey.ts: -------------------------------------------------------------------------------- 1 | import { IComb } from './IComb'; 2 | import { event_getCode, event_bind } from './utils'; 3 | import { CombHandler } from './CombHandler'; 4 | 5 | export const Hotkey = { 6 | on: function(combDef, fn, compo) { 7 | if (handler == null) init(); 8 | 9 | var comb = IComb.create( 10 | combDef 11 | , 'keydown' 12 | , fn 13 | , compo 14 | ); 15 | handler.attach(comb); 16 | }, 17 | off: function(fn){ 18 | handler.off(fn); 19 | }, 20 | handleEvent: function(event){ 21 | handler.handle(event.type, event_getCode(event), event); 22 | }, 23 | reset: function(){ 24 | handler.reset(); 25 | } 26 | }; 27 | 28 | var handler; 29 | function init() { 30 | handler = new CombHandler(); 31 | event_bind(window, 'keydown', Hotkey); 32 | event_bind(window, 'keyup', Hotkey); 33 | event_bind(window, 'focus', Hotkey.reset); 34 | } 35 | -------------------------------------------------------------------------------- /projects/mask-compo/src/keyboard/filters.ts: -------------------------------------------------------------------------------- 1 | 2 | export function filter_skippedInput (event, code){ 3 | if (event.ctrlKey || event.altKey) 4 | return false; 5 | return filter_isKeyboardInput(event.target); 6 | }; 7 | 8 | export function filter_skippedComponent (compo){ 9 | if (compo.$ == null || compo.$.length === 0) { 10 | return false; 11 | } 12 | return filter_skippedElement(compo.$.get(0)); 13 | }; 14 | export function filter_skippedElement (el) { 15 | if (document.contains(el) === false) 16 | return false; 17 | 18 | if (el.style.display === 'none') 19 | return false; 20 | 21 | var disabled = el.disabled; 22 | if (disabled === true) 23 | return false; 24 | 25 | return true; 26 | }; 27 | export function filter_isKeyboardInput (el) { 28 | var tag = el.tagName; 29 | if ('TEXTAREA' === tag) { 30 | return true; 31 | } 32 | if ('INPUT' !== tag) { 33 | return false; 34 | } 35 | return TYPELESS_INPUT.indexOf(' ' + el.type + ' ') === -1; 36 | }; 37 | 38 | const TYPELESS_INPUT = ' button submit checkbox file hidden image radio range reset '; 39 | -------------------------------------------------------------------------------- /projects/mask-compo/src/keyboard/utils.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export function event_bind (el, type, mix){ 4 | el.addEventListener(type, mix, false); 5 | }; 6 | export function event_unbind (el, type, mix) { 7 | el.removeEventListener(type, mix, false); 8 | }; 9 | 10 | export function event_getCode (event){ 11 | var code = event.keyCode || event.which; 12 | 13 | if (code >= 96 && code <= 105) { 14 | // numpad digits 15 | return code - 48; 16 | } 17 | 18 | return code; 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /projects/mask-compo/src/model/IAttrDefinition.ts: -------------------------------------------------------------------------------- 1 | export interface IAttrDefinition { 2 | default?: any 3 | type?: string 4 | name?: string 5 | } -------------------------------------------------------------------------------- /projects/mask-compo/src/scope-vars.ts: -------------------------------------------------------------------------------- 1 | import { _global, _document } from '@utils/refs' 2 | import { parser_ensureTemplateFunction } from '@core/parser/exports' 3 | import { log_warn } from '@core/util/reporters'; 4 | 5 | declare var exports; 6 | 7 | export var domLib; 8 | export var Class; 9 | 10 | 11 | export function _mask_ensureTmplFn (value) { 12 | return typeof value !== 'string' 13 | ? value 14 | : parser_ensureTemplateFunction(value) 15 | ; 16 | }; 17 | 18 | export function _resolve_External (key){ 19 | return _global[key] || _exports[key] || _atma[key] 20 | }; 21 | 22 | var _atma = _global.atma || {}, 23 | _exports = exports || {}; 24 | 25 | function resolve(a?,b?,c?) { 26 | for (var i = 0; i < arguments.length; i++) { 27 | var val = _resolve_External(arguments[i]); 28 | if (val != null) { 29 | return val; 30 | } 31 | } 32 | return null; 33 | } 34 | domLib = resolve('jQuery', 'Zepto', '$'); 35 | Class = resolve('Class'); 36 | 37 | export function setDomLib (lib) { 38 | domLib = lib; 39 | } 40 | 41 | //#if (DEBUG) 42 | if (_document != null && domLib == null) { 43 | log_warn('DomLite is used. You can set jQuery-Zepto-Kimbo via `mask.Compo.config.setDOMLibrary($)`'); 44 | } 45 | //#endif 46 | -------------------------------------------------------------------------------- /projects/mask-compo/src/touch/Handler.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Touch } from './Touch' 3 | import { FastClick } from './FastClick'; 4 | import { isTouchable } from '../util/event'; 5 | 6 | export const TouchHandler = { 7 | supports (type) { 8 | if (isTouchable === false) { 9 | return false; 10 | } 11 | switch(type){ 12 | case 'click': 13 | case 'mousedown': 14 | case 'mouseup': 15 | case 'mousemove': 16 | return true; 17 | } 18 | return false; 19 | }, 20 | on (el, type, fn, opts){ 21 | if ('click' === type) { 22 | return new FastClick(el, fn, opts); 23 | } 24 | return new Touch(el, type, fn, opts); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /projects/mask-compo/src/util/dfr.ts: -------------------------------------------------------------------------------- 1 | import { is_Function } from '@utils/is'; 2 | import { _global } from '@utils/refs' 3 | import { log_warn } from '@core/util/reporters'; 4 | 5 | 6 | export function dfr_isBusy(dfr) { 7 | if (dfr == null || typeof dfr.then !== 'function') return false; 8 | 9 | // Class.Deferred 10 | if (is_Function(dfr.isBusy)) return dfr.isBusy(); 11 | 12 | // jQuery Deferred 13 | if (is_Function(dfr.state)) return dfr.state() === 'pending'; 14 | 15 | if (dfr instanceof Promise) { 16 | return true; 17 | } 18 | 19 | log_warn('Class, jQuery or native promise expected'); 20 | return false; 21 | } 22 | 23 | const Promise = _global.Promise; 24 | -------------------------------------------------------------------------------- /projects/mask-compo/src/util/domLib.ts: -------------------------------------------------------------------------------- 1 | import { KeyboardHandler } from '../keyboard/Handler'; 2 | 3 | /** 4 | * Combine .filter + .find 5 | */ 6 | 7 | export function domLib_find ($set, selector) { 8 | return $set.filter(selector).add($set.find(selector)); 9 | }; 10 | 11 | export function domLib_on ($set, type, selector, fn) { 12 | if (selector == null) { 13 | return $set.on(type, fn); 14 | } 15 | if (KeyboardHandler.supports(type, selector)) { 16 | return $set.each(function(i, el){ 17 | KeyboardHandler.on(el, type, selector, fn); 18 | }); 19 | } 20 | return $set 21 | .on(type, selector, fn) 22 | .filter(selector) 23 | .on(type, fn); 24 | }; 25 | -------------------------------------------------------------------------------- /projects/mask-compo/src/util/slots.ts: -------------------------------------------------------------------------------- 1 | import { fn_apply } from '@utils/fn'; 2 | 3 | export function slots_mix (target, source) { 4 | for (var key in source) { 5 | 6 | if (target.hasOwnProperty(key) === false) { 7 | target[key] = source[key]; 8 | continue; 9 | } 10 | target[key] = slot_inherit(target[key], source[key]); 11 | } 12 | }; 13 | export function slot_inherit (handler, base) { 14 | // is called in controllers context 15 | return function(){ 16 | 17 | this.super = base; 18 | return fn_apply(handler, this, arguments); 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /projects/mask-compo/test/attr.spec.ts: -------------------------------------------------------------------------------- 1 | import { Mask as mask } from '@core/mask' 2 | 3 | const Compo = mask.Compo; 4 | 5 | UTest({ 6 | 'supports decorator' () { 7 | class Foo extends mask.Component { 8 | 9 | @mask.deco.attr() 10 | foo: string 11 | 12 | @mask.deco.attr({ name: 'barco' }) 13 | bar: string 14 | } 15 | 16 | mask.define('Foo', Foo); 17 | 18 | let owner = Compo.initialize(`Foo foo='hello' barco='world';`); 19 | let fooCompo = owner.find('Foo'); 20 | 21 | eq_(fooCompo.foo, 'hello'); 22 | eq_(fooCompo.bar, 'world'); 23 | } 24 | }); -------------------------------------------------------------------------------- /projects/mask-compo/test/examples/keyboard.spec.ts: -------------------------------------------------------------------------------- 1 | UTest({ 2 | async 'global hotkeys' () { 3 | const doc = await UTest 4 | .server 5 | .request('/projects/mask-compo/examples/keyboard/hotkeys.html'); 6 | 7 | await UTest.domtest(doc.body, ` 8 | 9 | do press('a'); 10 | find(.current) > has ('text', '- a'); 11 | 12 | do press('c+d'); 13 | find(.current) > has ('text', '- c+d'); 14 | 15 | do press('alt+e'); 16 | find(.current) > has ('text', '- alt+e'); 17 | 18 | do press('shift+a'); 19 | find(.current) > has ('text', '- shift+a'); 20 | 21 | do press('shift+1'); 22 | find(.current) > has ('text', '- shift+1'); 23 | 24 | do press('f8'); 25 | find(.current) > has ('text', '- f8'); 26 | 27 | do press('alt+ctrl+d'); 28 | find(.current) > has ('text', '- alt+ctrl+d'); 29 | 30 | do press('ctrl+d'); 31 | find(.current) > has ('text', '- ctrl+d'); 32 | 33 | do press('g'); 34 | do press('i'); 35 | find(.current) > has ('text', '- g,i'); 36 | 37 | do press('ctrl+g'); 38 | do press('ctrl+i'); 39 | find(.current) > has ('text', '- ctrl+g, ctrl+i'); 40 | `) 41 | } 42 | }) 43 | -------------------------------------------------------------------------------- /projects/mask-compo/test/pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { Mask as mask } from '@core/mask'; 2 | const Compo = mask.Compo; 3 | 4 | declare var sinon: sinon.SinonStatic 5 | 6 | 7 | UTest({ 8 | 'should emit piped signal on click' () { 9 | mask.registerHandler('Foo', Compo({ 10 | pipes: { 11 | testy: { 12 | foo: assert.await() 13 | } 14 | } 15 | })); 16 | 17 | var div = mask.render(` 18 | Foo > button x-pipe-signal='click: testy.foo'; 19 | `); 20 | 21 | return UTest.domtest(div, ` 22 | find(button) > do click; 23 | `); 24 | }, 25 | 'should manually fire the piped signal with arguments' () { 26 | var spy = sinon.spy(); 27 | mask.registerHandler('Foo', Compo({ 28 | pipes: { 29 | testy: { 30 | foo: spy 31 | } 32 | } 33 | })); 34 | 35 | var compo = Compo.initialize('a > Foo'); 36 | Compo.pipe('testy').emit('foo', 1, 'qux'); 37 | 38 | compo.remove(); 39 | Compo.pipe('testy').emit('foo', 2, 'quxy'); 40 | 41 | eq_(spy.callCount, 1); 42 | deepEq_(spy.args[0], [1, 'qux']); 43 | } 44 | }) 45 | -------------------------------------------------------------------------------- /projects/mask-compo/test/static.spec.ts: -------------------------------------------------------------------------------- 1 | import { Mask as mask } from '@core/mask' 2 | const Compo = mask.Compo; 3 | 4 | declare var sinon: sinon.SinonStatic 5 | 6 | UTest({ 7 | 'should attach the function to instance' () { 8 | var spyInner = sinon.spy(); 9 | var spyOuter = sinon.spy(); 10 | 11 | var foo: any = new (Compo({ 12 | someFn: spyInner 13 | })); 14 | 15 | Compo.attach(foo, 'someFn', spyOuter); 16 | foo.someFn('bar', 2); 17 | 18 | const expect = [['bar', 2]]; 19 | eq_(spyInner.callCount, 1); 20 | deepEq_(spyInner.args, expect); 21 | deepEq_(spyOuter.args, expect); 22 | } 23 | }) 24 | -------------------------------------------------------------------------------- /projects/mask-j/src/jmask/jMask.ts: -------------------------------------------------------------------------------- 1 | import { Dom } from '@core/dom/exports'; 2 | import { Proto } from './proto' 3 | import { ManipAttr } from './manip_attr' 4 | import { ManipClass } from './manip_class' 5 | import { ManipDom} from './manip_dom' 6 | import { Traverse } from './traverse' 7 | import { obj_extendMany } from '@utils/obj'; 8 | 9 | 10 | export function jMask (mix?) { 11 | if (this instanceof jMask === false) 12 | return new (jMask as any)(mix); 13 | if (mix == null) 14 | return this; 15 | if (mix.type === Dom.SET) 16 | return mix; 17 | return this.add(mix); 18 | } 19 | 20 | obj_extendMany( 21 | Proto, 22 | ManipAttr, 23 | ManipClass, 24 | ManipDom, 25 | Traverse, 26 | { constructor: jMask } 27 | ); 28 | 29 | jMask.prototype = Proto; 30 | -------------------------------------------------------------------------------- /projects/mask-j/src/jmask/jmask.ts: -------------------------------------------------------------------------------- 1 | import { Dom } from '@core/dom/exports'; 2 | import { Proto } from './proto' 3 | import { ManipAttr } from './manip_attr' 4 | import { ManipClass } from './manip_class' 5 | import { ManipDom} from './manip_dom' 6 | import { Traverse } from './traverse' 7 | import { obj_extendMany } from '@utils/obj'; 8 | 9 | 10 | export function jMask (mix?) { 11 | if (this instanceof jMask === false) 12 | return new (jMask as any)(mix); 13 | if (mix == null) 14 | return this; 15 | if (mix.type === Dom.SET) 16 | return mix; 17 | return this.add(mix); 18 | } 19 | 20 | obj_extendMany( 21 | Proto, 22 | ManipAttr, 23 | ManipClass, 24 | ManipDom, 25 | Traverse, 26 | { constructor: jMask } 27 | ); 28 | 29 | jMask.prototype = Proto; 30 | -------------------------------------------------------------------------------- /projects/mask-j/src/scope-vars.ts: -------------------------------------------------------------------------------- 1 | import { parser_ensureTemplateFunction, parser_parse } from '@core/parser/exports'; 2 | import { renderer_render } from '@core/renderer/exports'; 3 | 4 | export const _mask_render = renderer_render; 5 | export const _mask_parse = parser_parse; 6 | export const _mask_ensureTmplFnOrig = parser_ensureTemplateFunction; 7 | 8 | 9 | 10 | export function _mask_ensureTmplFn(value) { 11 | if (typeof value !== 'string') { 12 | return value; 13 | } 14 | return _mask_ensureTmplFnOrig(value); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /projects/mask-j/src/util/array.ts: -------------------------------------------------------------------------------- 1 | import { is_ArrayLike } from '@utils/is'; 2 | 3 | export function arr_eachAny(mix, fn) { 4 | if (is_ArrayLike(mix) === false) { 5 | fn(mix); 6 | return; 7 | } 8 | var imax = mix.length, 9 | i = -1; 10 | while (++i < imax) { 11 | fn(mix[i], i); 12 | } 13 | } 14 | 15 | export function arr_unique(array) { 16 | hasDuplicate_ = false; 17 | array.sort(sort); 18 | if (hasDuplicate_ === false) return array; 19 | 20 | var duplicates = [], 21 | i = 0, 22 | j = 0, 23 | imax = array.length - 1; 24 | 25 | while (i < imax) { 26 | if (array[i++] === array[i]) { 27 | duplicates[j++] = i; 28 | } 29 | } 30 | while (j--) { 31 | array.splice(duplicates[j], 1); 32 | } 33 | 34 | return array; 35 | } 36 | 37 | var hasDuplicate_ = false; 38 | function sort(a, b) { 39 | if (a === b) { 40 | hasDuplicate_ = true; 41 | return 0; 42 | } 43 | return 1; 44 | } 45 | -------------------------------------------------------------------------------- /projects/mask-node/examples/counter.js: -------------------------------------------------------------------------------- 1 | mask.registerHandler('Counter', Compo('Counter', { 2 | 3 | model: { 4 | visible: true 5 | }, 6 | slots: { 7 | 'foo' () { 8 | this.model.visible = false; 9 | } 10 | } 11 | })) 12 | -------------------------------------------------------------------------------- /projects/mask-node/examples/import/counter.mask: -------------------------------------------------------------------------------- 1 | define Counter { 2 | function onRenderStart () { 3 | this.model = { counter: 0 }; 4 | } 5 | slot increment () { 6 | this.model.counter++; 7 | } 8 | 9 | button x-tap = increment > 'Increment' 10 | tt { 11 | span > ' (current) ' 12 | i.current > '~[bind: counter]' 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /projects/mask-node/examples/import/doubleCounter.mask: -------------------------------------------------------------------------------- 1 | import Counter from './counter'; 2 | 3 | define DoubleCounter extends Counter { 4 | // extend slot 5 | slot increment () { 6 | this.model.counter += 2; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /projects/mask-node/examples/import/heading.mask: -------------------------------------------------------------------------------- 1 | h4 > 'Heading' -------------------------------------------------------------------------------- /projects/mask-node/examples/import/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /projects/mask-node/examples/import/index.mask: -------------------------------------------------------------------------------- 1 | import from './heading'; 2 | import from './counter'; 3 | import Counter as CounterRenamed from './counter'; 4 | import foo from './subcounter'; 5 | import DoubleCounter from './doubleCounter'; 6 | 7 | div name='counter-server' { 8 | p > i > 'Server render' 9 | Counter { 10 | div; 11 | } 12 | Counter; 13 | } 14 | hr; 15 | div name='counter-client' { 16 | p > i > 'Client render' 17 | Counter x-mode='client'; 18 | } 19 | hr; 20 | div name='counter-renamed-server' { 21 | p > i > '(renamed) Server render' 22 | CounterRenamed; 23 | } 24 | hr; 25 | div name='counter-renamed-client' { 26 | p > i > '(renamed) Client render' 27 | CounterRenamed x-mode='client'; 28 | } 29 | 30 | hr; 31 | div name='nested-counter-server' { 32 | p > i > '(nested) Server render' 33 | foo; 34 | } 35 | 36 | hr; 37 | div name='nested-counter-client' { 38 | p > i > '(nested) Client render' 39 | foo x-mode='client'; 40 | } 41 | 42 | hr; 43 | div name='nested-double-counter-server' { 44 | p > i > '(inheritance) Server. Double Counter' 45 | DoubleCounter; 46 | } 47 | 48 | hr; 49 | div name='nested-double-counter-client' { 50 | p > i > '(inheritance) Client. Double Counter' 51 | DoubleCounter x-mode='client'; 52 | } 53 | -------------------------------------------------------------------------------- /projects/mask-node/examples/import/subcounter.mask: -------------------------------------------------------------------------------- 1 | import Counter as CounterRenamed from './counter'; 2 | 3 | define foo { 4 | tt > i > ' subcounter ' 5 | CounterRenamed; 6 | } 7 | -------------------------------------------------------------------------------- /projects/mask-node/examples/index/index.mask: -------------------------------------------------------------------------------- 1 | var pages = [ 2 | '/define', 3 | '/import' 4 | ]; 5 | 6 | 7 | ul > for (page of pages) { 8 | li > a href='~[page]' > '~[page]' 9 | } 10 | -------------------------------------------------------------------------------- /projects/mask-node/examples/page/SimpleApp.mask: -------------------------------------------------------------------------------- 1 | import * as Controller from 'SimpleAppController.js'; 2 | 3 | define SimpleApp extends Controller { 4 | 5 | slot bumpVersion () { 6 | this.increment(); 7 | } 8 | 9 | h4 > 'Simple App' 10 | i > '~[bind: this.counter]' 11 | 12 | button x-tap='bumpVersion' > 'Bump' 13 | } 14 | 15 | -------------------------------------------------------------------------------- /projects/mask-node/examples/page/SimpleAppController.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | counter: 2, 3 | increment: function () { 4 | this.counter++; 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /projects/mask-node/examples/page/simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /projects/mask-node/src/bootstrap-wrapper.js: -------------------------------------------------------------------------------- 1 | (function (root, factory) { 2 | 'use strict'; 3 | 4 | 5 | var _name = 'di', 6 | _global = typeof window === 'undefined' ? global : window, 7 | _module = { 8 | exports: {} 9 | }; 10 | 11 | factory(_global, _module, _module.exports); 12 | 13 | if (typeof mask === 'undefined') { 14 | throw new Error('Mask should be loaded globally'); 15 | } 16 | 17 | mask.Compo.bootstrap = _module.exports.bootstrap; 18 | 19 | }(this, function (global, module, exports) { 20 | 'use strict'; 21 | 22 | /**MODULE**/ 23 | 24 | })); 25 | -------------------------------------------------------------------------------- /projects/mask-node/src/builder/dom/build.ts: -------------------------------------------------------------------------------- 1 | import { builder_buildDelegate } from '@core/builder/delegate/exports'; 2 | import { HtmlDom } from '@mask-node/html-dom/exports'; 3 | 4 | export const builder_build = builder_buildDelegate({ 5 | document: HtmlDom.document, 6 | create (name, doc) { 7 | return doc.createElement(name); 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /projects/mask-node/src/cache/utils.ts: -------------------------------------------------------------------------------- 1 | 2 | export function cache_toHtmlDelegate(html) { 3 | return function(){ 4 | return html; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /projects/mask-node/src/client/mock.ts: -------------------------------------------------------------------------------- 1 | 2 | export function mock_appendChildDelegate(container) { 3 | return function (element) { 4 | return container.appendChild(element); 5 | }; 6 | }; 7 | export function mock_Container(container, elements) { 8 | this.container = container; 9 | this.elements = elements; 10 | }; 11 | export function mock_ContainerByAnchor(el) { 12 | this.last = el; 13 | }; 14 | 15 | 16 | // protos 17 | 18 | mock_ContainerByAnchor.prototype.appendChild = function (child) { 19 | let next = this.last.nextSibling, 20 | parent = this.last.parentNode; 21 | 22 | if (next) 23 | parent.insertBefore(child, next); 24 | else 25 | parent.appendChild(child); 26 | 27 | this.last = child; 28 | }; 29 | 30 | 31 | mock_Container.prototype = { 32 | _after: function () { 33 | return this.elements[this.elements.length - 1] || this.container; 34 | }, 35 | _before: function () { 36 | return this.elements[0] || this.container; 37 | }, 38 | appendChild: function (child) { 39 | let last = this._after(); 40 | 41 | if (last.nextSibling) { 42 | last.parentNode.insertBefore(child, last.nextSibling); 43 | return; 44 | } 45 | 46 | last.parentNode.appendChild(child); 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /projects/mask-node/src/client/setup-attr.ts: -------------------------------------------------------------------------------- 1 | import { trav_getElement } from './traverse'; 2 | import { custom_Attributes } from './vars'; 3 | 4 | export function setup_attr(meta, node, model, ctx, container, ctr) { 5 | let handler = custom_Attributes[meta.name]; 6 | if (handler == null) { 7 | console.warn('Custom Attribute Handler was not defined', meta.name); 8 | return; 9 | } 10 | 11 | let el = trav_getElement(node); 12 | if (el == null){ 13 | console.error('Browser has cut off nested tag for the comment', node); 14 | return; 15 | } 16 | 17 | handler(null, meta.value, model, ctx, el, ctr, container); 18 | } 19 | -------------------------------------------------------------------------------- /projects/mask-node/src/client/setup-el.ts: -------------------------------------------------------------------------------- 1 | import { setup } from './setup'; 2 | 3 | export function setup_el(node, model, ctx, container, ctr, children) { 4 | 5 | if (node.nodeType === Node.ELEMENT_NODE) { 6 | if (children != null) 7 | children.push(node); 8 | 9 | if (node.firstChild) 10 | setup(node.firstChild, model, ctx, node, ctr); 11 | } 12 | 13 | let nextSibling = node.nextSibling; 14 | if (nextSibling != null && children == null) { 15 | setup(nextSibling, model, ctx, container, ctr); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /projects/mask-node/src/client/traverse.ts: -------------------------------------------------------------------------------- 1 | export function trav_getElements(meta) { 2 | if (meta.isDocument) 3 | return Array.prototype.slice.call(document.body.childNodes); 4 | 5 | 6 | var id = 'mask-htmltemplate-' + meta.ID, 7 | startNode = document.getElementById(id), 8 | endNode = document.getElementsByName(id)[0]; 9 | 10 | if (startNode == null || endNode == null) { 11 | console.error('Invalid node range to initialize mask components'); 12 | return null; 13 | } 14 | 15 | var array = [], 16 | node = startNode.nextSibling; 17 | while (node != null && node != endNode) { 18 | array.push(node); 19 | 20 | node = node.nextSibling; 21 | } 22 | 23 | return array; 24 | }; 25 | export function trav_getElement(node) { 26 | var next = node.nextSibling; 27 | while (next && next.nodeType !== Node.ELEMENT_NODE) { 28 | next = next.nextSibling; 29 | } 30 | 31 | return next; 32 | }; 33 | export function trav_getMeta(node) { 34 | while (node && node.nodeType !== Node.COMMENT_NODE) { 35 | node = node.nextSibling; 36 | } 37 | return node; 38 | }; 39 | -------------------------------------------------------------------------------- /projects/mask-node/src/client/utils.ts: -------------------------------------------------------------------------------- 1 | export function util_extendObj_(a, b) { 2 | if (a == null) 3 | return b; 4 | if (b == null) 5 | return a; 6 | 7 | for (var key in b) { 8 | a[key] = b[key]; 9 | } 10 | return a; 11 | }; 12 | export function util_pushComponents_(a, b) { 13 | var aCompos = a.components || [], 14 | bCompos = b.components || []; 15 | if (bCompos.length === 0) 16 | return; 17 | a.components = aCompos.concat(bCompos); 18 | }; 19 | -------------------------------------------------------------------------------- /projects/mask-node/src/client/vars.ts: -------------------------------------------------------------------------------- 1 | declare var mask; 2 | 3 | const custom_Attributes = mask.getAttrHandler(); 4 | const custom_Tags = mask.getHandlers(); 5 | const custom_Utils = mask.getUtil(); 6 | const Dom = mask.Dom; 7 | const log_warn = mask.log.warn; 8 | 9 | let rootModel; 10 | let rootID; 11 | 12 | 13 | export { 14 | custom_Attributes, 15 | custom_Tags, 16 | custom_Utils, 17 | Dom, 18 | log_warn, 19 | } 20 | 21 | 22 | export function setRootModel (models) { 23 | rootModel = models; 24 | } 25 | export function getRootModel () { 26 | return rootModel; 27 | } 28 | export function setRootID (ID) { 29 | rootID = ID; 30 | } 31 | export function getRootID () { 32 | return rootID; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /projects/mask-node/src/const.ts: -------------------------------------------------------------------------------- 1 | export const mode_SERVER = 'server'; 2 | export const mode_SERVER_ALL = 'server:all'; 3 | export const mode_SERVER_CHILDREN = 'server:children'; 4 | export const mode_CLIENT = 'client'; 5 | export const mode_BOTH = 'both'; 6 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/CommentNode.ts: -------------------------------------------------------------------------------- 1 | export class CommentNode { 2 | nextSibling = null 3 | parentNode = null 4 | textContent = '' 5 | 6 | constructor (textContent: string) { 7 | var str = textContent; 8 | if (str == null) { 9 | return; 10 | } 11 | if (_isComment(str)) { 12 | str = _stripComment(str); 13 | } 14 | this.textContent = str.replace(/\-\->/g, '-->'); 15 | } 16 | toString() { 17 | if (this.textContent === '') 18 | return ''; 19 | 20 | return ''; 21 | } 22 | }; 23 | 24 | function _isComment(txt) { 25 | if (txt.charCodeAt(0) !== 60/*<*/ 26 | && txt.charCodeAt(1) !== 33/*!*/ 27 | && txt.charCodeAt(1) !== 45/*-*/ 28 | && txt.charCodeAt(2) !== 45/*-*/) 29 | return false; 30 | 31 | var l = txt.length; 32 | if (txt.charCodeAt(--l) !== 62/*>*/ 33 | && txt.charCodeAt(--l) !== 45/*-*/ 34 | && txt.charCodeAt(--l) !== 45/*-*/) 35 | return false; 36 | 37 | return true; 38 | } 39 | function _stripComment(txt) { 40 | return txt.slice(4, -3); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/DoctypeNodeInn.ts: -------------------------------------------------------------------------------- 1 | import { class_createEx } from '@utils/class'; 2 | import { DomB } from './DomB'; 3 | import { ElementNodeInn } from './ElementNodeInn'; 4 | 5 | export class DoctypeNodeInn extends ElementNodeInn { 6 | nodeType = DomB.DOCTYPE 7 | 8 | toString () { 9 | return DEFAULT; 10 | } 11 | write (stream) { 12 | stream.write(DEFAULT); 13 | } 14 | }; 15 | 16 | var DEFAULT = ''; 17 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/DocumentFragmentInn.ts: -------------------------------------------------------------------------------- 1 | import { NodeBase } from './NodeBase'; 2 | import { DomB } from './DomB'; 3 | import { is_Function } from '@utils/is'; 4 | 5 | export class DocumentFragmentInn extends NodeBase { 6 | nodeType = DomB.FRAGMENT 7 | toString() { 8 | var element = this.firstChild, 9 | string = ''; 10 | 11 | while (element != null) { 12 | string += element.toString(); 13 | element = element.nextSibling; 14 | } 15 | return string; 16 | } 17 | write(stream) { 18 | var element = this.firstChild; 19 | while (element != null) { 20 | if ('write' in element && is_Function((element as any).write)) { 21 | (element as any).write(stream); 22 | } else { 23 | stream.write(element.toString()); 24 | } 25 | element = element.nextSibling; 26 | if (element != null) { 27 | stream.newline(); 28 | } 29 | } 30 | return stream; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/DomB.ts: -------------------------------------------------------------------------------- 1 | import { Dom } from '@core/dom/exports' 2 | import { obj_extend } from '@utils/obj'; 3 | 4 | export const DomB = obj_extend(Dom, { 5 | DOCTYPE: 11, 6 | UTILNODE: 12 7 | }); 8 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/TextNodeInn.ts: -------------------------------------------------------------------------------- 1 | 2 | import { DomB } from './DomB'; 3 | import { NodeBase } from './NodeBase'; 4 | 5 | export class TextNodeInn extends NodeBase { 6 | nodeType = DomB.TEXTNODE 7 | 8 | textContent = '' 9 | 10 | constructor (text) { 11 | super(); 12 | this.textContent = String(text == null ? '' : text); 13 | } 14 | toString () { 15 | return escape(this.textContent); 16 | } 17 | }; 18 | 19 | function escape(html) { 20 | return html 21 | .replace(/&/g, '&') 22 | .replace(//g, '>') 24 | ; 25 | } 26 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/UtilNodeInn.ts: -------------------------------------------------------------------------------- 1 | import { DomB } from './DomB'; 2 | import { Meta } from '@mask-node/helper/Meta'; 3 | import { NodeBase } from './NodeBase'; 4 | 5 | export class UtilNodeInn extends NodeBase { 6 | meta = null 7 | nodeType = DomB.UTILNODE 8 | 9 | 10 | constructor (type, name, value, attrName) { 11 | super(); 12 | this.meta = { 13 | utilType: type, 14 | utilName: name, 15 | value: value, 16 | attrName: attrName, 17 | current: null 18 | }; 19 | } 20 | // seems is implenented in NodeBase 21 | // appendChild (el) { 22 | // this.firstChild = el; 23 | // } 24 | toString () { 25 | var json = this.meta, 26 | info = { 27 | type: 'u', 28 | single: this.firstChild == null 29 | }, 30 | string = Meta.stringify(json, info); 31 | 32 | if (this.firstChild == null) 33 | return string; 34 | 35 | 36 | return string 37 | + this.firstChild.toString() 38 | + Meta.close(json, info) 39 | ; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/exports.ts: -------------------------------------------------------------------------------- 1 | import { DomB } from './DomB' 2 | import { CommentNode } from './CommentNode' 3 | import { ComponentNode } from './ComponentNode'; 4 | import { ElementNodeInn } from './ElementNodeInn'; 5 | import { TextNodeInn } from './TextNodeInn'; 6 | import { ScriptElementInn } from './ScriptElementInn'; 7 | import { UtilNodeInn } from './UtilNodeInn'; 8 | import { DocumentFragmentInn } from './DocumentFragmentInn'; 9 | import { documentInn } from './documentInn'; 10 | import { stringifyInn } from './util/stringify'; 11 | import { DoctypeNodeInn } from './DoctypeNodeInn'; 12 | import { setDocument } from '@utils/refs'; 13 | 14 | export namespace HtmlDom { 15 | export const document = documentInn; 16 | export const DocumentFragment = DocumentFragmentInn; 17 | 18 | export const Comment = CommentNode; 19 | export const Component = ComponentNode; 20 | export const DOCTYPE = DoctypeNodeInn 21 | export const Element = ElementNodeInn; 22 | export const TextNode = TextNodeInn; 23 | export const ScriptElement = ScriptElementInn; 24 | export const UtilNode = UtilNodeInn; 25 | 26 | export const Dom = DomB; 27 | 28 | export const stringify = stringifyInn; 29 | } 30 | 31 | 32 | // Set document to refs to be accessable from other modules 33 | setDocument(documentInn); 34 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/jq/classList.ts: -------------------------------------------------------------------------------- 1 | import { sel_classIndex } from './util/selector'; 2 | 3 | export class ClassList { 4 | 5 | attr 6 | className 7 | 8 | constructor(node) { 9 | this.attr = node.attributes; 10 | this.className = this.attr['class'] || ''; 11 | } 12 | 13 | get length() { 14 | return this.className.split(/\s+/).length; 15 | } 16 | 17 | contains(_class) { 18 | return sel_classIndex(this.className, _class) !== -1; 19 | } 20 | remove(_class) { 21 | var index = sel_classIndex(this.className, _class); 22 | if (index === -1) 23 | return; 24 | 25 | var str = this.className; 26 | 27 | this.className = 28 | this.attr['class'] = 29 | str.substring(0, index) + str.substring(index + _class.length); 30 | 31 | } 32 | add(_class) { 33 | if (sel_classIndex(this.className, _class) !== -1) 34 | return; 35 | 36 | this.className = 37 | this.attr['class'] = this.className 38 | + (this.className === '' ? '' : ' ') 39 | + _class; 40 | } 41 | }; -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/jq/exports.ts: -------------------------------------------------------------------------------- 1 | var jQ = (function(){ 2 | 3 | 4 | 5 | function jQ(mix) { 6 | if (this instanceof jQ === false) 7 | return new jQ(mix); 8 | 9 | 10 | if (mix == null) 11 | return this; 12 | 13 | if (mix instanceof jQ) 14 | return mix; 15 | 16 | 17 | return this.add(mix); 18 | } 19 | 20 | 21 | jQ.prototype = { 22 | length: 0, 23 | 24 | add: function(){ 25 | 26 | } 27 | 28 | } 29 | 30 | }()); 31 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/jq/traverse.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atmajs/MaskJS/f3951546aa9b5ada57fe66a35e7fa4809108f6c2/projects/mask-node/src/html-dom/jq/traverse.ts -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/tags.ts: -------------------------------------------------------------------------------- 1 | export const SingleTags = { 2 | 'area': 1, 3 | 'base': 1, 4 | 'br': 1, 5 | 'col': 1, 6 | 'embed': 1, 7 | 'hr': 1, 8 | 'img': 1, 9 | 'input': 1, 10 | 'keygen': 1, 11 | 'link': 1, 12 | 'menuitem': 1, 13 | 'meta': 1, 14 | 'param': 1, 15 | 'source': 1, 16 | 'track': 1, 17 | 'wbr': 1 18 | }; 19 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/util/html.ts: -------------------------------------------------------------------------------- 1 | import { is_String } from '@utils/is'; 2 | 3 | export function html_serializeAttributes(node) { 4 | var attr = node.attributes, 5 | str = '', 6 | key, value 7 | for (key in attr) { 8 | value = attr[key]; 9 | if (is_String(value)) { 10 | value = value.replace(/"/g, '"'); 11 | } 12 | str += ' ' + key + '="' + value + '"'; 13 | } 14 | return str; 15 | }; 16 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/util/node.ts: -------------------------------------------------------------------------------- 1 | export function node_insertBefore(node, anchor) { 2 | return anchor.parentNode.insertBefore(node, anchor); 3 | }; 4 | export function node_empty(node) { 5 | while (node.firstChild != null) { 6 | node.removeChild(node.firstChild); 7 | } 8 | }; -------------------------------------------------------------------------------- /projects/mask-node/src/html-dom/util/traverse.ts: -------------------------------------------------------------------------------- 1 | import { DomB } from '../DomB'; 2 | import { Component } from '@compo/exports'; 3 | 4 | // @Obsolete, remove `:document` component for for doctype. 5 | export function trav_getDoc(el, _deep?) { 6 | if (el != null && el.nodeType === DomB.FRAGMENT) 7 | el = el.firstChild; 8 | 9 | if (el == null) { 10 | return null; 11 | } 12 | if (el.compoName === ':document') { 13 | return el; 14 | } 15 | if (_deep == null) { 16 | _deep = 0; 17 | } 18 | if (_deep === 4) { 19 | return null; 20 | } 21 | 22 | var doc; 23 | doc = trav_getDoc(el.nextSibling, _deep); 24 | 25 | if (doc) { 26 | return doc; 27 | } 28 | return trav_getDoc(el.firstChild, ++_deep); 29 | }; 30 | 31 | 32 | export function trav_getChild(parent, tagName) { 33 | var el = parent.firstChild; 34 | while (el && el.tagName !== tagName) { 35 | el = el.nextSibling; 36 | } 37 | return el; 38 | }; 39 | -------------------------------------------------------------------------------- /projects/mask-node/src/html-page/exports.ts: -------------------------------------------------------------------------------- 1 | import { _scripts_handleSync, _scripts_handleAsync } from './scripts'; 2 | import { _transformMaskAutoTemplates, _transformAddingMaskBootstrap } from './transform'; 3 | import { rendererB_render, rendererB_renderHtmlDomAsync, rendererB_toHtml } from '@mask-node/renderer/exports'; 4 | 5 | export const HtmlPage = { 6 | render: function (tmpl, model, ctx) { 7 | var ast; 8 | 9 | ast = _scripts_handleSync(tmpl, model, ctx); 10 | ast = _transformMaskAutoTemplates(ast); 11 | 12 | return rendererB_render(ast, model, ctx); 13 | }, 14 | renderAsync: function (tmpl, model, ctx) { 15 | 16 | return _scripts_handleAsync(tmpl, model, ctx) 17 | .then(function (ast) { 18 | var ast2 = _transformMaskAutoTemplates(ast); 19 | 20 | if (ctx && ctx.config && ctx.config.shouldAppendBootstrap) { 21 | _transformAddingMaskBootstrap(ast2, ctx.config.maskBootstrapPath); 22 | } 23 | return rendererB_renderHtmlDomAsync(ast2, model, ctx) 24 | .then(function (dom, model, ctx, compo) { 25 | 26 | 27 | return rendererB_toHtml(dom, model, ctx, compo); 28 | }) 29 | }); 30 | }, 31 | } 32 | -------------------------------------------------------------------------------- /projects/mask-node/src/mask.ts: -------------------------------------------------------------------------------- 1 | import { Mask } from '@core/mask' 2 | 3 | import { obj_extend } from '@utils/obj'; 4 | import { 5 | rendererB_toHtml, 6 | rendererB_render, 7 | rendererB_renderAsync, 8 | rendererB_renderHtmlDomAsync, 9 | rendererB_build, 10 | rendererB_buildAsync 11 | } from './renderer/exports'; 12 | import { HtmlDom } from './html-dom/exports'; 13 | import { HtmlPage } from './html-page/exports'; 14 | 15 | import './util/loaders' 16 | import './mock/mock' 17 | import './handlers/document' 18 | 19 | 20 | 21 | obj_extend(Mask, { 22 | toHtml: rendererB_toHtml, 23 | render: rendererB_render, 24 | renderAsync: rendererB_renderAsync, 25 | renderHtmlDomAsync: rendererB_renderHtmlDomAsync, 26 | renderPage: HtmlPage.render, 27 | renderPageAsync: HtmlPage.renderAsync, 28 | 29 | build: rendererB_build, 30 | buildAsync: rendererB_buildAsync, 31 | 32 | document: HtmlDom.document 33 | }); 34 | -------------------------------------------------------------------------------- /projects/mask-node/src/mock/mock.ts: -------------------------------------------------------------------------------- 1 | import { Mask } from '@core/mask'; 2 | import { custom_Tags_defs, custom_Tags } from '@core/custom/exports'; 3 | 4 | import { obj_extend } from '@utils/obj'; 5 | import { mock_TagHandler } from './tag-handler'; 6 | 7 | 8 | 9 | Mask.compoDefinitions = function (compos, utils, attributes) { 10 | var tags = custom_Tags, 11 | defs = custom_Tags_defs; 12 | 13 | for (var tagName in compos) { 14 | defs[tagName] = compos[tagName]; 15 | 16 | if (tags[tagName] !== void 0) { 17 | obj_extend(tags[tagName].prototype, compos[tagName]); 18 | continue; 19 | } 20 | 21 | tags[tagName] = mock_TagHandler.create(tagName, null, 'client'); 22 | } 23 | 24 | var doNothing = function () { }; 25 | for (var key in utils) { 26 | if (utils[key].mode === 'client') { 27 | Mask.registerUtil(key, doNothing, 'client'); 28 | } 29 | } 30 | 31 | for (var key in attributes) { 32 | if (attributes[key].mode === 'client') { 33 | Mask.registerAttrHandler(key, doNothing, 'client'); 34 | } 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /projects/mask-node/src/node-wrapper.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MaskJS v%IMPORT(version)% 3 | * Part of the Atma.js Project 4 | * http://atmajs.com/ 5 | * 6 | * MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | * (c) 2012, %IMPORT(year)% Atma.js and other contributors 10 | */ 11 | (function (root, factory) { 12 | 13 | 14 | var mask = factory(global, module.exports); 15 | 16 | module.exports = mask; 17 | 18 | }(this, function (global, exports) { 19 | 'use strict'; 20 | 21 | var document; 22 | 23 | /**MODULE**/ 24 | 25 | var Mask = mask_1.Mask; 26 | 27 | document = Mask.document; 28 | return (exports.mask = Mask); 29 | })); 30 | -------------------------------------------------------------------------------- /projects/mask-node/src/util/compo.ts: -------------------------------------------------------------------------------- 1 | export function compo_wrapOnTagName(compo, node) { 2 | if (compo.tagName == null 3 | || compo.tagName === node.tagName 4 | || compo.tagName === compo.compoName) 5 | return; 6 | 7 | compo.nodes = { 8 | tagName: compo.tagName, 9 | attr: compo.attr, 10 | nodes: compo.nodes, 11 | type: 1 12 | }; 13 | }; -------------------------------------------------------------------------------- /projects/mask-node/src/util/ctx.ts: -------------------------------------------------------------------------------- 1 | 2 | export function ctx_stringify(ctx) { 3 | var has = false, obj = {}, x; 4 | for (var key in ctx) { 5 | if (key.charCodeAt(0) === 95 /*_*/) { 6 | continue; 7 | } 8 | x = ctx[key]; 9 | 10 | var type = typeof x; 11 | if (x == null 12 | || type === 'object' /* skip complex objects */ 13 | || type === 'function') { 14 | continue; 15 | } 16 | if (key === 'async') { 17 | continue; 18 | } 19 | 20 | has = true; 21 | obj[key] = x; 22 | } 23 | 24 | return has === false ? null : obj; 25 | }; -------------------------------------------------------------------------------- /projects/mask-node/src/util/json.ts: -------------------------------------------------------------------------------- 1 | import { is_Object, is_Array } from '@utils/is'; 2 | 3 | export function json_dimissCircular(mix) { 4 | if (is_Object(mix)) { 5 | cache = []; 6 | mix = clone(mix); 7 | cache = null; 8 | } 9 | return mix; 10 | }; 11 | 12 | var cache; 13 | 14 | function clone(mix) { 15 | 16 | if (is_Array(mix)) { 17 | var arr = [], 18 | imax = mix.length, 19 | i = -1; 20 | while (++i < imax) { 21 | arr[i] = clone(mix[i]); 22 | } 23 | return arr; 24 | } 25 | 26 | if (is_Object(mix)) { 27 | if (cache.indexOf(mix) !== -1) 28 | return '[object Circular]'; 29 | 30 | cache.push(mix); 31 | var obj = {}; 32 | for (var key in mix) { 33 | obj[key] = clone(mix[key]); 34 | } 35 | return obj; 36 | } 37 | 38 | return mix; 39 | } -------------------------------------------------------------------------------- /projects/mask-node/src/util/loaders.ts: -------------------------------------------------------------------------------- 1 | import { __cfg } from '@core/api/config'; 2 | import { class_Dfr } from '@utils/class/Dfr'; 3 | import { path_resolveCurrent, path_isRelative, path_combine, path_toLocalFile } from '@core/util/path'; 4 | 5 | declare var require; 6 | 7 | __cfg.getFile ??= function (path) { 8 | var dfr = new class_Dfr; 9 | var fs = require('fs'); 10 | var filename = path_toLocalFile(resolvePath(path)); 11 | fs.readFile(filename, 'utf8', function (error, str) { 12 | if (error != null) { 13 | dfr.reject({ 14 | message: error.toString(), 15 | status: error.code 16 | }); 17 | return; 18 | } 19 | dfr.resolve(str); 20 | }); 21 | return dfr; 22 | }; 23 | __cfg.getScript ??= function (path) { 24 | var dfr = new class_Dfr; 25 | var filename = path_toLocalFile(resolvePath(path)); 26 | 27 | try { 28 | var x = require(filename); 29 | dfr.resolve(x); 30 | } catch (error) { 31 | dfr.reject(error); 32 | } 33 | return dfr; 34 | }; 35 | 36 | var base_ = path_toLocalFile(path_resolveCurrent()); 37 | function resolvePath(path) { 38 | if (path_isRelative(path)) { 39 | return path_combine(base_, path); 40 | } 41 | return path; 42 | } 43 | -------------------------------------------------------------------------------- /projects/mask-node/src/util/node.ts: -------------------------------------------------------------------------------- 1 | import { is_Array } from '@utils/is'; 2 | import { custom_Tags } from '@core/custom/exports'; 3 | 4 | export function node_getType(node) { 5 | var type = node.type; 6 | if (type == null) { 7 | // in case if node was added manually, but type was not set 8 | 9 | if (is_Array(node)) { 10 | type = 10 11 | } 12 | else if (node.tagName != null) { 13 | type = 1; 14 | } 15 | else if (node.content != null) { 16 | type = 2; 17 | } 18 | } 19 | 20 | if (type === 1 && custom_Tags[node.tagName] != null) { 21 | // check if the tag name was overriden 22 | type = 4; 23 | } 24 | 25 | return type; 26 | }; 27 | -------------------------------------------------------------------------------- /projects/mask-node/src/util/path.ts: -------------------------------------------------------------------------------- 1 | import { path_normalize, path_isRelative, path_combine } from '@core/util/path'; 2 | 3 | declare var process; 4 | 5 | export function path_toLocalFile(path) { 6 | path = path_normalize(path); 7 | if (path_isRelative(path)) { 8 | path = '/' + path; 9 | } 10 | if (path.charCodeAt(0) === 47 /*/*/) { 11 | return path_combine(cwd(), path); 12 | } 13 | if (path.indexOf('file://') === 0) { 14 | path = path.replace('file://', ''); 15 | } 16 | if (/^\/\w+:\//.test(path)) { 17 | path = path.substring(1); 18 | } 19 | return path; 20 | }; 21 | 22 | function cwd() { 23 | return path_normalize(process.cwd()); 24 | } -------------------------------------------------------------------------------- /projects/mask-node/test/config-d.js: -------------------------------------------------------------------------------- 1 | include.cfg('amd', true); 2 | -------------------------------------------------------------------------------- /projects/mask-node/test/dom/feature/define.spec.ts: -------------------------------------------------------------------------------- 1 | import { $render } from '../utils'; 2 | 3 | UTest({ 4 | async 'component with binded model and a slot' () { 5 | var template = ` 6 | define Foo { 7 | slot change () { 8 | this.model.name = 'bar' 9 | } 10 | function onRenderStart() { 11 | this.model = { name: 'foo' }; 12 | } 13 | function onRenderEnd() { 14 | this.foo = 'foo'; 15 | } 16 | span > '~[bind: name]' 17 | button x-tap='change' > 'Change' 18 | } 19 | 20 | Foo; 21 | `; 22 | var model = { 23 | numbers: [2, 3, 4] 24 | } 25 | let { el, doc, win } = await $render(template, { model }) 26 | let fooCompo = win.app.find('Foo'); 27 | 28 | notEq_(fooCompo, null); 29 | eq_(fooCompo.foo, 'foo'); 30 | return UTest.domtest(el, ` 31 | find('span') > text foo; 32 | find('button') > do click; 33 | find('span') > text bar; 34 | `); 35 | } 36 | }) 37 | -------------------------------------------------------------------------------- /projects/mask-node/test/dom/feature/import.spec.ts: -------------------------------------------------------------------------------- 1 | UTest({ 2 | 3 | }) 4 | -------------------------------------------------------------------------------- /projects/mask-node/test/dom/statement/with.spec.ts: -------------------------------------------------------------------------------- 1 | import { $render } from '../utils'; 2 | 3 | UTest({ 4 | async 'simple' () { 5 | var template = 'with (foo) > "~[bar]"'; 6 | var model = { 7 | foo: { bar: 'bar' } 8 | }; 9 | 10 | let {el} = await $render(template, { model }) 11 | eq_(el.textContent, 'bar'); 12 | }, 13 | async 'model from scope' () { 14 | var template = 'with (foo) > "~[bar]"'; 15 | var controller = { 16 | scope: { 17 | foo: { bar: 'bar' } 18 | } 19 | }; 20 | 21 | let {el} = await $render(template, { controller }) 22 | eq_(el.textContent, 'bar'); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /projects/mask-node/test/dom/statement_bind/each.spec.ts: -------------------------------------------------------------------------------- 1 | import { $render } from '../utils'; 2 | 3 | UTest({ 4 | 5 | async 'simple' () { 6 | var template = ` 7 | #container { 8 | +each (letters) > 9 | span > '~[.]' 10 | } 11 | `; 12 | var model = { 13 | letters: ['A', 'B'] 14 | }; 15 | 16 | let {el, doc, win } = await $render(template, { model }); 17 | var model_ = win.app.model; 18 | has_(model_, model); 19 | has_(model_, '__observers'); 20 | 21 | var arr = model_.letters; 22 | eq_(el.textContent, 'AB'); 23 | 24 | arr.push('C'); 25 | eq_(el.textContent, 'ABC'); 26 | 27 | arr.unshift('Z'); 28 | eq_(el.textContent, 'ZABC'); 29 | 30 | arr.splice(1, 2); 31 | eq_(el.textContent, 'ZC'); 32 | }, 33 | 34 | }) 35 | -------------------------------------------------------------------------------- /projects/mask-node/test/dom/statement_bind/for.spec.ts: -------------------------------------------------------------------------------- 1 | import { $render } from '../utils'; 2 | 3 | UTest({ 4 | 'for..of': { 5 | async 'simple' () { 6 | var template = '+for (x of numbers) > span > "~[x]"'; 7 | var model = { 8 | numbers: [2, 3, 4] 9 | } 10 | let {el, win} = await $render(template, { model }) 11 | var model_ = win.app.model; 12 | has_(model_, model); 13 | has_(model_, '__observers'); 14 | 15 | eq_(el.textContent, '234'); 16 | 17 | model_.numbers.push(5); 18 | eq_(el.textContent, '2345'); 19 | 20 | model_.numbers.unshift(1); 21 | eq_(el.textContent, '12345'); 22 | 23 | model_.numbers.splice(1, 3); 24 | eq_(el.textContent, '15'); 25 | }, 26 | } 27 | }) 28 | -------------------------------------------------------------------------------- /projects/mask-node/test/dom/statement_bind/with.spec.ts: -------------------------------------------------------------------------------- 1 | import { $render } from '../utils'; 2 | 3 | UTest({ 4 | async 'simple render on server and change on client' () { 5 | var template = ` 6 | +with (user) { 7 | h4 > '~[name]' 8 | h6 > '~[role]' 9 | } 10 | `; 11 | var model = { 12 | user: { 13 | name: 'Foo', 14 | role: 'admin' 15 | } 16 | }; 17 | 18 | let {el, win, doc} = await $render(template, { model }) 19 | var model_ = win.app.model; 20 | has_(model_, model); 21 | has_(model_, '__observers'); 22 | 23 | checkWithModel(el, model_.user); 24 | 25 | model_.user = { 26 | name: 'Baz', 27 | role: 'editor' 28 | }; 29 | checkWithModel(el, model_.user); 30 | 31 | 32 | function checkWithModel(el, user) { 33 | $(el) 34 | .find('h4') 35 | .eq_('text', user.name) 36 | .end() 37 | .find('h6') 38 | .eq_('text', user.role); 39 | } 40 | 41 | } 42 | }) 43 | -------------------------------------------------------------------------------- /projects/mask-node/test/examples/html.spec.ts: -------------------------------------------------------------------------------- 1 | UTest({ 2 | $config: { 3 | 'http.process': { 4 | command: 'atma custom projects/mask-node/examples/index', 5 | matchReady: '/Listen /' 6 | } 7 | }, 8 | 9 | 'import' (done) { 10 | UTest 11 | .server 12 | .request('http://localhost:5771/page/simple') 13 | .done(function(doc, win){ 14 | 15 | UTest 16 | .domtest(doc.body, ` 17 | find ('i') > text ('2'); 18 | find ('button') > do click; 19 | find ('i') > text ('3'); 20 | `) 21 | .always(done); 22 | }); 23 | } 24 | }) 25 | -------------------------------------------------------------------------------- /projects/mask-node/test/node/attr/x.spec.ts: -------------------------------------------------------------------------------- 1 | UTest({ 2 | 'template' () { 3 | mask.define('Foo', mask.Compo({ 4 | meta: { 5 | attributes: { 6 | num: 'number' 7 | } 8 | } 9 | })); 10 | var root = mask.Compo.initialize('Foo num = 10;'); 11 | var foo = root.find('Foo'); 12 | eq_(foo.xNum, 10); 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /projects/mask-node/test/node/content.spec.ts: -------------------------------------------------------------------------------- 1 | // import { documentInn } from '@mask-node/html-dom/documentInn'; 2 | // import { rendererB_render } from '@mask-node/renderer/exports'; 3 | // global.document = documentInn; 4 | 5 | declare var MaskNode; 6 | 7 | 8 | 9 | UTest({ 10 | 'same lib' () { 11 | eq_(mask, MaskNode); 12 | }, 13 | 'style' () { 14 | var template = ` 15 | div { 16 | style { 17 | foo > .name { 18 | color: #fff; 19 | } 20 | } 21 | } 22 | `; 23 | 24 | const html = MaskNode.render(template); 25 | 26 | 27 | has_(html, ' .name'); 29 | } 30 | }) 31 | -------------------------------------------------------------------------------- /projects/mask-node/test/node/feature/decorators.spec.ts: -------------------------------------------------------------------------------- 1 | UTest({ 2 | 'should add class before render' () { 3 | mask.defineDecorator('active', { 4 | beforeRender (node) { 5 | node.attr.class = 'foo-active'; 6 | } 7 | }); 8 | 9 | var html = mask.render(` 10 | [active] 11 | div; 12 | `); 13 | eq_(html, '
'); 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /projects/mask-node/test/node/feature/import.spec.ts: -------------------------------------------------------------------------------- 1 | UTest({ 2 | 'import template' () { 3 | var tmpl = ` 4 | import from '/test/tmpl/a'; 5 | `; 6 | 7 | return mask 8 | .renderAsync(tmpl) 9 | .done(html => { 10 | has_(html, '>a'); 11 | }); 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /projects/mask-node/test/node/parser/script.spec.ts: -------------------------------------------------------------------------------- 1 | UTest({ 2 | 'attributes' () { 3 | var tmpl = `script type='text/mask'>'>div<'` 4 | var html = mask.render(tmpl); 5 | 6 | has_(html, 'text/mask'); 7 | has_(html, '>div<'); 8 | }, 9 | 'do not interpolate' () { 10 | var tmpl = `script >' div > "~[foo]" '` 11 | var html = mask.render(tmpl); 12 | 13 | has_(html, ' div > "~[foo]" '); 14 | }, 15 | 'interpolate' () { 16 | var tmpl = `script > :html > '(~[foo])'` 17 | var html = mask.render(tmpl, { foo: '_foo_' }); 18 | 19 | has_(html, ''); 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /projects/mask-node/test/tmpl/a.mask: -------------------------------------------------------------------------------- 1 | h4 > 'a' -------------------------------------------------------------------------------- /projects/mask-node/test/tmpl/compos/bar.ts: -------------------------------------------------------------------------------- 1 | mask.registerHandler(':bar', mask.Compo({ 2 | template: ".container > each(.) > div name='~[.]';", 3 | onRenderStart () { 4 | this.model = ['a', 'b', 'c']; 5 | } 6 | })); 7 | -------------------------------------------------------------------------------- /projects/mask-node/test/tmpl/compos/clientAsyncCompo.ts: -------------------------------------------------------------------------------- 1 | mask.registerHandler('ClientAsyncCompo', mask.Compo({ 2 | template: ` 3 | define Listener { 4 | var meta = { 5 | mode: 'client' 6 | }; 7 | #foo > 'Name: ~[$.parent.foo]' 8 | } 9 | Listener; 10 | `, 11 | onRenderStartClient () { 12 | return mask.class.Deferred.run(resolve => { 13 | setTimeout(() => { 14 | this.foo = 'Foo'; 15 | resolve(); 16 | }, 200); 17 | }); 18 | } 19 | })); 20 | -------------------------------------------------------------------------------- /projects/mask-node/test/tmpl/compos/clientCompo.ts: -------------------------------------------------------------------------------- 1 | mask.registerHandler('ClientCompo', mask.Compo({ 2 | meta: { 3 | mode: 'client' 4 | }, 5 | template: "#foo > '~[.]'", 6 | onRenderStart () { 7 | this.model = 'FooTitle'; 8 | } 9 | })); 10 | -------------------------------------------------------------------------------- /projects/mask-node/test/tmpl/compos/foo.mask: -------------------------------------------------------------------------------- 1 | input value='~[text]'; 2 | 3 | button x-signal="mousedown:changeToQux" { 4 | "Change to baz" 5 | } 6 | -------------------------------------------------------------------------------- /projects/mask-node/test/tmpl/compos/foo.ts: -------------------------------------------------------------------------------- 1 | include 2 | .load('foo.mask') 3 | .done(function(resp){ 4 | 5 | mask.registerHandler(':foo', mask.Compo({ 6 | tagName: 'div', 7 | template: resp.load.foo, 8 | onRenderStart: function(){ 9 | 10 | this.model = { 11 | text: 'foo' 12 | }; 13 | }, 14 | 15 | compos: { 16 | 'test_jQuery': '$: button', 17 | 'test_querySelector': 'button' 18 | }, 19 | 20 | events: { 21 | 'click: button': function(){ 22 | 23 | this.$.find('input').val('baz'); 24 | } 25 | }, 26 | 27 | slots: { 28 | changeToQux: function(event){ 29 | 30 | this.$.find('input').val('qux'); 31 | } 32 | } 33 | })); 34 | 35 | }); 36 | -------------------------------------------------------------------------------- /projects/mask-node/test/tmpl/compos/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /projects/mask-node/test/tmpl/import/letters/a.mask: -------------------------------------------------------------------------------- 1 | import A from './a_upper'; 2 | 3 | define a { 4 | span name='a_lower' > 'a'; 5 | A; 6 | } 7 | -------------------------------------------------------------------------------- /projects/mask-node/test/tmpl/import/letters/a_upper.mask: -------------------------------------------------------------------------------- 1 | define A { 2 | span name='a_upper' > 'A' 3 | } 4 | -------------------------------------------------------------------------------- /projects/mask-node/test/tmpl/import/letters/b.html: -------------------------------------------------------------------------------- 1 | 2 | import * as B from 'b_upper.html'; 3 | 4 | 5 | b 6 | 7 | -------------------------------------------------------------------------------- /projects/mask-node/test/tmpl/import/letters/letters.mask: -------------------------------------------------------------------------------- 1 | import a from 'a'; 2 | import b from 'b.html'; 3 | 4 | a; 5 | b; -------------------------------------------------------------------------------- /projects/observer/src/exports.ts: -------------------------------------------------------------------------------- 1 | export { 2 | obj_addObserver, 3 | obj_hasObserver, 4 | obj_removeObserver, 5 | obj_addMutatorObserver, 6 | obj_removeMutatorObserver, 7 | obj_lockObservers, 8 | obj_unlockObservers 9 | } from './obj_observe' 10 | 11 | export { 12 | expression_bind, 13 | expression_unbind, 14 | expression_callFn, 15 | expression_createBinder, 16 | expression_createListener 17 | } from './expression' 18 | -------------------------------------------------------------------------------- /projects/observer/src/obj_stream.ts: -------------------------------------------------------------------------------- 1 | import { obj_addObserver, obj_removeObserver } from './obj_observe'; 2 | 3 | class Stream { 4 | constructor (public ctx: any, public property: string) { 5 | } 6 | subscribe(cb: (val: T) => void ) { 7 | obj_addObserver(this.ctx, this.property, cb); 8 | return new Subscription(this, cb); 9 | } 10 | } 11 | class Subscription { 12 | constructor (public stream: Stream, public cb: Function) { 13 | } 14 | unsubscribe () { 15 | obj_removeObserver( 16 | this.stream.ctx, 17 | this.stream.property, 18 | this.cb 19 | ); 20 | } 21 | } 22 | 23 | export function obj_stream (ctx: any, property) { 24 | return new Stream(ctx, property); 25 | }; -------------------------------------------------------------------------------- /projects/observer/src/utils/obj.ts: -------------------------------------------------------------------------------- 1 | 2 | export function obj_callMethod (obj: any, path: string, args?: any[]) { 3 | var end = path.lastIndexOf('.'); 4 | if (end === -1) { 5 | return call(obj, path, args); 6 | } 7 | var host = obj, 8 | i = -1; 9 | while (host != null && i !== end) { 10 | var start = i; 11 | i = path.indexOf('.', i); 12 | 13 | var key = path.substring(start + 1, i); 14 | host = host[key]; 15 | } 16 | return call(host, path.substring(end + 1), args); 17 | }; 18 | function call(obj: any, key: string, args?: any[]) { 19 | const fn = obj == null ? null : obj[key]; 20 | if (typeof fn !== 'function') { 21 | console.error('Not a function', key); 22 | return null; 23 | } 24 | return fn.apply(obj, args); 25 | } 26 | -------------------------------------------------------------------------------- /projects/observer/test/stream.spec.ts: -------------------------------------------------------------------------------- 1 | import { obj_stream } from '../src/obj_stream'; 2 | import sinon = require('sinon'); 3 | 4 | UTest({ 5 | 'create stream' () { 6 | let obj = { letter: 'a' }; 7 | let stream = obj_stream(obj, 'letter'); 8 | 9 | let fn = sinon.spy(); 10 | let subscription = stream.subscribe(fn); 11 | 12 | obj.letter = 'd'; 13 | obj.letter = 'c'; 14 | 15 | eq_(fn.callCount, 2); 16 | deepEq_(fn.args, [ 17 | ['d'], 18 | ['c'] 19 | ]); 20 | 21 | subscription.unsubscribe(); 22 | 23 | obj.letter = 'e'; 24 | eq_(fn.callCount, 2); 25 | } 26 | }) -------------------------------------------------------------------------------- /src/arch/Module.ts: -------------------------------------------------------------------------------- 1 | export const ModuleMidd = { 2 | parseMaskContent (mix: string | any, path: string): PromiseLike<{ [key: string]: any }> { 3 | throw new Error('Not set'); 4 | } 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /src/autoreload/StateTree.ts: -------------------------------------------------------------------------------- 1 | import { Mask } from '../mask' 2 | declare let mask: typeof Mask; 3 | 4 | export interface IStateTreeNode { 5 | compoName: string 6 | state: any 7 | components: IStateTreeNode[] 8 | } 9 | 10 | export function stateTree_serialize (compo): IStateTreeNode { 11 | return mask.TreeWalker.map(compo, function (x) { 12 | return { 13 | compoName: x.compoName, 14 | state: x.serializeState && (x.serializeState() || {}), 15 | components: null 16 | }; 17 | }); 18 | } 19 | export function stateTree_deserialize (compo, stateTree: IStateTreeNode) { 20 | let ctx = {}; 21 | mask.TreeWalker.superpose(compo, stateTree, function (x, stateNode: IStateTreeNode) { 22 | if (stateNode.state != null && x.deserializeState) { 23 | x.deserializeState(stateNode.state, ctx, compo); 24 | } 25 | }); 26 | } -------------------------------------------------------------------------------- /src/autoreload/wrapper.js: -------------------------------------------------------------------------------- 1 | (function(mask) { 2 | 'use strict'; 3 | 4 | /**MODULE**/ 5 | 6 | }(mask)); -------------------------------------------------------------------------------- /src/builder/BuilderData.ts: -------------------------------------------------------------------------------- 1 | export const BuilderData = { 2 | id: 1, 3 | document: typeof document === 'undefined' ? null : document 4 | }; -------------------------------------------------------------------------------- /src/builder/ctx.ts: -------------------------------------------------------------------------------- 1 | import { obj_extend } from '@utils/obj'; 2 | import { class_Dfr } from '@utils/class/Dfr'; 3 | 4 | export class builder_Ctx extends class_Dfr { 5 | constructor (data?){ 6 | super(); 7 | if (data != null) { 8 | obj_extend(this, data); 9 | } 10 | } 11 | // Is true, if some of the components in a ctx is async 12 | async = false 13 | // List of busy components 14 | defers = null as any[] /*Array*/ 15 | 16 | // NodeJS 17 | // Track components ID 18 | _id = 0 19 | // ModelsBuilder for HTML serialization 20 | _models = null 21 | 22 | // ModulesBuilder fot HTML serialization 23 | _modules = null 24 | 25 | _redirect = null as string 26 | _rewrite = null as string 27 | 28 | static clone (ctx: builder_Ctx){ 29 | let data = {}; 30 | for(let key in ctx) { 31 | if (key in PRIVATE === false) { 32 | data[key] = ctx[key]; 33 | } 34 | } 35 | return new builder_Ctx(data); 36 | } 37 | }; 38 | 39 | const PRIVATE = { 40 | async: 1, 41 | defers: 1, 42 | _id: 0, 43 | _models: 1, 44 | _modules: 1, 45 | _redirect: 1, 46 | _rewrite: 1, 47 | } -------------------------------------------------------------------------------- /src/builder/delegate/IBuilderConfig.ts: -------------------------------------------------------------------------------- 1 | export interface IBuilderConfig { 2 | document?: Document 3 | create: (name: string, doc: any) => any; 4 | //build_compoFactory?: (build: Function, config: IBuilderConfig) => (node, model_, ctx, container_, ctr_, children_?) => any 5 | } -------------------------------------------------------------------------------- /src/builder/delegate/build_decorators.ts: -------------------------------------------------------------------------------- 1 | import { Decorator } from '@core/feature/decorators/exports'; 2 | import { error_withNode } from '@core/util/reporters'; 3 | 4 | export function decorators_buildFactory (build: Function) { 5 | return function decorators_build (decorators, node, model, ctx, el, ctr, els) { 6 | var type = Decorator.getDecoType(node); 7 | if (type == null) { 8 | error_withNode('Unsupported node to decorate', node); 9 | return build(node, model, ctx, el, ctr, els); 10 | } 11 | if (type === 'NODE') { 12 | var builder = Decorator.wrapNodeBuilder(decorators, build, model, ctx, ctr); 13 | return builder(node, model, ctx, el, ctr, els); 14 | } 15 | if (type === 'COMPO') { 16 | var builder = Decorator.wrapCompoBuilder(decorators, build, model, ctx, ctr); 17 | return builder(node, model, ctx, el, ctr, els); 18 | } 19 | if (type === 'METHOD') { 20 | Decorator.wrapMethodNode(decorators, node, model, ctx, ctr); 21 | return build(node, model, ctx, el, ctr, els); 22 | } 23 | }; 24 | } -------------------------------------------------------------------------------- /src/builder/delegate/build_many.ts: -------------------------------------------------------------------------------- 1 | import { Decorator } from '@core/feature/decorators/exports'; 2 | import { decorators_buildFactory } from './build_decorators'; 3 | 4 | export function build_manyFactory (build: Function) { 5 | let decorators_build = decorators_buildFactory(build); 6 | 7 | return function build_many (nodes, model, ctx, el, ctr, els){ 8 | if (nodes == null) return; 9 | var imax = nodes.length; 10 | for(var i = 0; i < imax; i++) { 11 | var x = nodes[i]; 12 | if (x.type === 16) { 13 | var start = i; 14 | i = Decorator.goToNode(nodes, i, imax); 15 | var decos = nodes.slice(start, i); 16 | decorators_build(decos, nodes[i], model, ctx, el, ctr, els); 17 | continue; 18 | } 19 | 20 | build(x, model, ctx, el, ctr, els); 21 | } 22 | }; 23 | } -------------------------------------------------------------------------------- /src/builder/delegate/exports.ts: -------------------------------------------------------------------------------- 1 | import { builder_buildFactory } from './builder_buildFactory'; 2 | import { IBuilderConfig } from './IBuilderConfig'; 3 | 4 | export function builder_buildDelegate (opts: IBuilderConfig){ 5 | return builder_buildFactory(opts); 6 | }; 7 | -------------------------------------------------------------------------------- /src/builder/dom/build.ts: -------------------------------------------------------------------------------- 1 | import { builder_buildDelegate } from '../delegate/exports'; 2 | 3 | export const builder_build = builder_buildDelegate({ 4 | create (name, doc) { 5 | return doc.createElement(name); 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /src/builder/exports.ts: -------------------------------------------------------------------------------- 1 | export { builder_Ctx } from './ctx' 2 | export { BuilderData } from './BuilderData' 3 | export { builder_build } from './dom/build' 4 | export { builder_buildSVG } from './svg/build' 5 | export { builder_resumeDelegate } from './resume' 6 | 7 | -------------------------------------------------------------------------------- /src/builder/svg/build.ts: -------------------------------------------------------------------------------- 1 | import { builder_buildDelegate } from '../delegate/exports'; 2 | 3 | export const builder_buildSVG = builder_buildDelegate({ 4 | create (name, doc) { 5 | return doc.createElementNS(SVG_NS, name); 6 | } 7 | }); 8 | 9 | const SVG_NS = 'http://www.w3.org/2000/svg'; 10 | -------------------------------------------------------------------------------- /src/custom/IUtilType.ts: -------------------------------------------------------------------------------- 1 | export type IUtilType = 'compo-attr' | 'compo-prop' | 'prop' | 'attr' | 'node'; 2 | -------------------------------------------------------------------------------- /src/custom/exports.ts: -------------------------------------------------------------------------------- 1 | export { 2 | custom_optimize 3 | } from './optimize'; 4 | 5 | export { 6 | custom_Utils, 7 | custom_Statements, 8 | custom_Attributes, 9 | custom_Tags, 10 | custom_Tags_global, 11 | custom_Tags_defs, 12 | custom_Parsers, 13 | custom_Parsers_Transform, 14 | custom_Optimizers 15 | } from './repositories'; 16 | 17 | export { 18 | customAttr_register, 19 | customAttr_get 20 | } from './attribute'; 21 | import './mock-attributes'; 22 | 23 | export { 24 | customUtil_get, 25 | customUtil_$utils, 26 | customUtil_register 27 | } from './util'; 28 | 29 | import './mock-utils'; 30 | 31 | export { 32 | customTag_get, 33 | customTag_getAll, 34 | customTag_register, 35 | customTag_registerScoped, 36 | customTag_registerFromTemplate, 37 | customTag_registerResolver, 38 | customTag_Resolver, 39 | customTag_Compo_getHandler, 40 | customTag_define, 41 | customTag_Base 42 | } from './tag'; 43 | 44 | import './mock-tags'; 45 | 46 | export { 47 | customStatement_register, 48 | customStatement_get 49 | } from './statement'; 50 | 51 | -------------------------------------------------------------------------------- /src/custom/mock-attributes.ts: -------------------------------------------------------------------------------- 1 | export const forMaskNode = true; 2 | -------------------------------------------------------------------------------- /src/custom/mock-tags.ts: -------------------------------------------------------------------------------- 1 | export const forMaskNode = true; 2 | -------------------------------------------------------------------------------- /src/custom/mock-utils.ts: -------------------------------------------------------------------------------- 1 | export const forMaskNode = true; 2 | -------------------------------------------------------------------------------- /src/custom/optimize.ts: -------------------------------------------------------------------------------- 1 | import { obj_toFastProps } from '@utils/obj'; 2 | import { 3 | custom_Attributes, 4 | custom_Statements, 5 | custom_Tags, 6 | custom_Parsers, 7 | custom_Parsers_Transform 8 | } from './repositories'; 9 | 10 | export function custom_optimize (){ 11 | let i = _arr.length; 12 | while (--i > -1) { 13 | readProps(_arr[i]); 14 | } 15 | i = _arr.length; 16 | while(--i > -1) { 17 | defineProps(_arr[i]); 18 | obj_toFastProps(_arr[i]); 19 | } 20 | obj_toFastProps(custom_Attributes); 21 | }; 22 | let _arr = [ 23 | custom_Statements, 24 | custom_Tags, 25 | custom_Parsers, 26 | custom_Parsers_Transform 27 | ]; 28 | let _props = {}; 29 | 30 | function readProps(obj) { 31 | for (let key in obj) { 32 | _props[key] = null; 33 | } 34 | } 35 | function defineProps(obj) { 36 | for (let key in _props) { 37 | if (obj[key] === void 0) { 38 | obj[key] = null; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/custom/statement.ts: -------------------------------------------------------------------------------- 1 | import { is_Function } from '@utils/is'; 2 | import { custom_Statements } from './repositories'; 3 | 4 | /** 5 | * Register a statement handler 6 | * @param {string} name - Tag name to handle 7 | * @param {StatementHandler} handler 8 | * @memberOf mask 9 | * @method registerStatement 10 | */ 11 | export function customStatement_register (name, handler){ 12 | //@TODO should it be not allowed to override system statements, if, switch? 13 | custom_Statements[name] = is_Function(handler) 14 | ? { render: handler } 15 | : handler 16 | ; 17 | }; 18 | /** 19 | * Get statement handler 20 | * @param {string} name 21 | * @returns {StatementHandler} 22 | * @memberOf mask 23 | * @method getStatement 24 | */ 25 | export function customStatement_get (name){ 26 | return name != null 27 | ? custom_Statements[name] 28 | : custom_Statements 29 | ; 30 | }; 31 | /** 32 | * Is called when the builder matches the node by tagName 33 | * @callback StatementHandler 34 | * @param {MaskNode} node 35 | * @param {object} model 36 | * @param {object} ctx 37 | * @param {DomNode} container 38 | * @param {object} parentComponent 39 | * @param {Array} children - `out` Fill the array with rendered elements 40 | */ 41 | -------------------------------------------------------------------------------- /src/dom/ComponentNode.ts: -------------------------------------------------------------------------------- 1 | import { dom_COMPONENT } from './NodeType'; 2 | 3 | export function ComponentNode(compoName?, parent?, controller?){ 4 | this.tagName = compoName; 5 | this.parent = parent; 6 | this.controller = controller; 7 | this.attr = {}; 8 | } 9 | ComponentNode.prototype = { 10 | constructor: ComponentNode, 11 | type: dom_COMPONENT, 12 | parent: null, 13 | attr: null, 14 | controller: null, 15 | nodes: null, 16 | components: null, 17 | model: null, 18 | modelRef: null 19 | }; 20 | -------------------------------------------------------------------------------- /src/dom/DecoratorNode.ts: -------------------------------------------------------------------------------- 1 | import { class_create } from '@utils/class'; 2 | import { dom_DECORATOR } from './NodeType'; 3 | 4 | export const DecoratorNode = class_create({ 5 | constructor: function DecoratorNode (expression, parent) { 6 | this.expression = expression; 7 | this.parent = parent; 8 | }, 9 | __single: true, 10 | expression: null, 11 | parent: null, 12 | sourceIndex: -1, 13 | type: dom_DECORATOR, 14 | stringify: function(stream) { 15 | stream.newline(); 16 | stream.write('[' + this.expression + ']'); 17 | } 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /src/dom/Fragment.ts: -------------------------------------------------------------------------------- 1 | import { class_create } from '@utils/class'; 2 | import { dom_FRAGMENT } from './NodeType'; 3 | import { _appendChild } from './utils'; 4 | 5 | export const Fragment = class_create({ 6 | type: dom_FRAGMENT, 7 | nodes: null, 8 | appendChild: _appendChild, 9 | source: '', 10 | filename: '', 11 | syntax: 'mask', 12 | parent: null 13 | }); 14 | export const HtmlFragment = class_create(Fragment, { 15 | syntax: 'html' 16 | }); -------------------------------------------------------------------------------- /src/dom/INode.ts: -------------------------------------------------------------------------------- 1 | export interface INode { 2 | __single: boolean 3 | 4 | type: number 5 | tagName: string 6 | 7 | attr: {[name: string]: any} 8 | props: {[name: string]: any} 9 | expression: string 10 | nodes: INode[] 11 | nextSibling: INode 12 | 13 | parent: INode 14 | sourceIndex: number 15 | 16 | 17 | decorators: any 18 | 19 | stringify (stream); 20 | appendChild (el); 21 | 22 | constructor (tagName: string, parent?: INode) 23 | } 24 | -------------------------------------------------------------------------------- /src/dom/Node.ts: -------------------------------------------------------------------------------- 1 | import { class_create } from '@utils/class' 2 | import { _appendChild } from './utils'; 3 | import { dom_NODE } from './NodeType'; 4 | import { INode } from './INode'; 5 | /** 6 | * @name MaskNode 7 | * @type {class} 8 | * @property {type} [type=1] 9 | * @property {object} attr 10 | * @property {string} tagName 11 | * @property {Array.} nodes 12 | * @property {IMaskNode} parent 13 | * @property {string} [expression] 14 | * @property {function} appendChild 15 | * @memberOf mask.Dom 16 | */ 17 | export const Node = <(new (...args) => INode)>class_create({ 18 | constructor: function Node(tagName, parent) { 19 | this.type = dom_NODE; 20 | this.tagName = tagName; 21 | this.parent = parent; 22 | this.attr = {}; 23 | }, 24 | __single: null, 25 | appendChild: _appendChild, 26 | attr: null, 27 | props: null, 28 | expression: null, 29 | nodes: null, 30 | parent: null, 31 | sourceIndex: -1, 32 | stringify: null, 33 | tagName: null, 34 | type: dom_NODE, 35 | decorators: null, 36 | nextSibling: null 37 | }); 38 | -------------------------------------------------------------------------------- /src/dom/NodeType.ts: -------------------------------------------------------------------------------- 1 | export const dom_NODE = 1; 2 | export const dom_TEXTNODE = 2; 3 | export const dom_FRAGMENT = 3; 4 | export const dom_COMPONENT = 4; 5 | export const dom_CONTROLLER = 9; 6 | export const dom_SET = 10; 7 | export const dom_STATEMENT = 15; 8 | export const dom_DECORATOR = 16; 9 | -------------------------------------------------------------------------------- /src/dom/TextNode.ts: -------------------------------------------------------------------------------- 1 | import { class_create } from '@utils/class' 2 | import { _appendChild } from './utils'; 3 | import { dom_TEXTNODE } from './NodeType'; 4 | 5 | /** 6 | * @name TextNode 7 | * @type {class} 8 | * @property {type} [type=2] 9 | * @property {(string|function)} content 10 | * @property {IMaskNode} parent 11 | * @memberOf mask.Dom 12 | */ 13 | export const TextNode = class_create({ 14 | constructor: function(text, parent) { 15 | this.content = text; 16 | this.parent = parent; 17 | }, 18 | type: dom_TEXTNODE, 19 | content: null as string | Function, 20 | parent: null, 21 | sourceIndex: -1 22 | }); 23 | -------------------------------------------------------------------------------- /src/dom/exports.ts: -------------------------------------------------------------------------------- 1 | import { 2 | dom_NODE, 3 | dom_TEXTNODE, 4 | dom_FRAGMENT, 5 | dom_COMPONENT, 6 | dom_CONTROLLER, 7 | dom_SET, 8 | dom_STATEMENT, 9 | dom_DECORATOR 10 | } from './NodeType'; 11 | 12 | import { TextNode } from './TextNode'; 13 | import { Fragment, HtmlFragment } from './Fragment'; 14 | import { Node } from './Node'; 15 | 16 | import { DecoratorNode } from './DecoratorNode'; 17 | 18 | import { ComponentNode } from './ComponentNode'; 19 | 20 | export const Dom = { 21 | NODE: dom_NODE, 22 | TEXTNODE: dom_TEXTNODE, 23 | FRAGMENT: dom_FRAGMENT, 24 | COMPONENT: dom_COMPONENT, 25 | CONTROLLER: dom_CONTROLLER, 26 | SET: dom_SET, 27 | STATEMENT: dom_STATEMENT, 28 | DECORATOR: dom_DECORATOR, 29 | 30 | Node: Node, 31 | TextNode: TextNode, 32 | Fragment: Fragment, 33 | HtmlFragment: HtmlFragment, 34 | Component: ComponentNode, 35 | DecoratorNode: DecoratorNode 36 | }; 37 | -------------------------------------------------------------------------------- /src/dom/utils.ts: -------------------------------------------------------------------------------- 1 | export function _appendChild(el){ 2 | el.parent = this; 3 | var nodes = this.nodes; 4 | if (nodes == null) { 5 | this.nodes = [el]; 6 | return; 7 | } 8 | 9 | var length = nodes.length; 10 | if (length !== 0) { 11 | var prev = nodes[length - 1]; 12 | if (prev != null) { 13 | prev.nextSibling = el; 14 | } 15 | } 16 | 17 | nodes.push(el); 18 | } -------------------------------------------------------------------------------- /src/feature/decorators/decorators-desc.ts: -------------------------------------------------------------------------------- 1 | // # 1. Method Node decorator 2 | 3 | // # 1.1 Target Fn 4 | /** 5 | * Take a function and return a function. 6 | * @param {function} targetFn - Function wich schould be wrapped 7 | * @returns {function} New function 8 | */ 9 | function MyMethodNodeDecorator (targetFn) { 10 | return new Function; 11 | } 12 | 13 | // # 1.2 Invoke Interceptors 14 | /** 15 | * An interface with optionally implmented methods: `beforeInvoke(args)`, `afterInvoke` 16 | * @param {function} targetFn - Function wich schould be wrapped 17 | * @returns {function} New function 18 | */ 19 | function MyMethodNodeDecorator (interceptors) { 20 | var { beforeInvoke, afterInvoke } = interceptors; 21 | 22 | beforeInvoke = function (args) { 23 | return overridenArgs || void 0; 24 | }; 25 | afterInvoke = function (result) { 26 | return overridenResult || void 0; 27 | } 28 | } -------------------------------------------------------------------------------- /src/feature/decorators/store.ts: -------------------------------------------------------------------------------- 1 | export const _store = {}; -------------------------------------------------------------------------------- /src/feature/exports.ts: -------------------------------------------------------------------------------- 1 | // import run 2 | // import merge 3 | // import optimize 4 | // import modules/ 5 | // import methods/ 6 | // import decorators/ 7 | // import Define 8 | // import Di 9 | // import TreeWalker -------------------------------------------------------------------------------- /src/feature/methods/IMethodNode.ts: -------------------------------------------------------------------------------- 1 | import { INode } from '@core/dom/INode'; 2 | 3 | export interface IMethodNode extends INode { 4 | name: string 5 | body: string 6 | args: IMethodArg[] 7 | 8 | 9 | flagAsync: boolean 10 | flagPrivate: boolean 11 | flagPublic: boolean 12 | flagStatic: boolean 13 | flagSelf: boolean 14 | } 15 | 16 | 17 | export interface IMethodArg { 18 | prop: string 19 | type: string 20 | } -------------------------------------------------------------------------------- /src/feature/methods/exports.ts: -------------------------------------------------------------------------------- 1 | import { defMethods_getSource, defMethods_compile } from './define-methods'; 2 | import { nodeMethod_getSource, nodeMethod_compile } from './node-method'; 3 | 4 | import './parsers' 5 | import './handlers' 6 | 7 | 8 | export const Methods = { 9 | getSourceForDefine: defMethods_getSource, 10 | compileForDefine: defMethods_compile, 11 | 12 | getSourceForNode: nodeMethod_getSource, 13 | compileForNode: nodeMethod_compile, 14 | }; 15 | -------------------------------------------------------------------------------- /src/feature/methods/scope-refs.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export function scopeRefs_getImportVars (owner, out_) { 4 | var imports = getImports(owner); 5 | if (imports == null) { 6 | return; 7 | } 8 | var out = out_ || [[],[]], 9 | imax = imports.length, 10 | i = -1, 11 | arr; 12 | while ( ++i < imax ) { 13 | var import_ = imports[i]; 14 | var type = import_.type; 15 | if (type !== 'script' && type !== 'data' && type !== 'text' && type !== 'mask') { 16 | continue; 17 | } 18 | import_.eachExport(register); 19 | } 20 | function register(varName) { 21 | var val = this.getExport(varName); 22 | out[0].push(varName); 23 | out[1].push(val); 24 | } 25 | }; 26 | 27 | function getImports (owner) { 28 | if (owner.importItems) return owner.importItems; 29 | 30 | var x = owner; 31 | while(x != null && x.tagName !== 'imports') { 32 | x = x.parent; 33 | } 34 | return x == null ? null : x.importItems; 35 | } 36 | -------------------------------------------------------------------------------- /src/feature/methods/utils.ts: -------------------------------------------------------------------------------- 1 | 2 | export function _args_toCode (args) { 3 | var str = ''; 4 | if (args == null || args.length === 0) { 5 | return str; 6 | } 7 | var imax = args.length, 8 | i = -1; 9 | while(++i < imax){ 10 | if (i > 0) str += ','; 11 | str += args[i].prop; 12 | } 13 | return str; 14 | }; 15 | -------------------------------------------------------------------------------- /src/feature/modules/Import/ImportData.ts: -------------------------------------------------------------------------------- 1 | import { i_Types } from './ImportTypes'; 2 | import { class_create } from '@utils/class'; 3 | import { ImportScript } from './ImportScript'; 4 | 5 | export const ImportData = i_Types['data'] = class_create(ImportScript, { 6 | type: 'data', 7 | contentType: 'json' 8 | }); -------------------------------------------------------------------------------- /src/feature/modules/Import/ImportHtml.ts: -------------------------------------------------------------------------------- 1 | import { i_Types } from './ImportTypes'; 2 | import { class_create } from '@utils/class'; 3 | import { ImportMask } from './ImportMask'; 4 | 5 | export const ImportHtml = i_Types['html'] = class_create(ImportMask, { 6 | type: 'mask', 7 | contentType: 'html' 8 | }); -------------------------------------------------------------------------------- /src/feature/modules/Import/ImportMask.ts: -------------------------------------------------------------------------------- 1 | import { IImport } from './Import'; 2 | import { i_Types } from './ImportTypes'; 3 | import { class_create } from '@utils/class'; 4 | 5 | export const ImportMask = i_Types['mask'] = class_create(IImport, { 6 | type: 'mask', 7 | contentType: 'mask', 8 | getHandler: function(name){ 9 | var module = this.module; 10 | if (module == null) { 11 | return; 12 | } 13 | if (module.error != null) { 14 | if (this.hasExport(name)) { 15 | this.logError_('Resource for the import `' + name + '` not loaded'); 16 | return this.empty; 17 | } 18 | return null 19 | } 20 | var x = this.getExportedName(name); 21 | if (x == null) { 22 | return null; 23 | } 24 | return module.exports[x] || module.queryHandler(x); 25 | }, 26 | empty: function EmptyCompo () {} 27 | }); -------------------------------------------------------------------------------- /src/feature/modules/Import/ImportScript.ts: -------------------------------------------------------------------------------- 1 | import { IImport } from './Import'; 2 | import { i_Types } from './ImportTypes'; 3 | import { class_create } from '@utils/class'; 4 | 5 | export const ImportScript = i_Types['script'] = class_create(IImport, { 6 | type: 'script', 7 | contentType: 'script' 8 | }); -------------------------------------------------------------------------------- /src/feature/modules/Import/ImportStyle.ts: -------------------------------------------------------------------------------- 1 | import { IImport } from './Import'; 2 | import { i_Types } from './ImportTypes'; 3 | import { class_create } from '@utils/class'; 4 | import { fn_doNothing } from '@utils/fn'; 5 | 6 | export const ImportStyle = i_Types['style'] = class_create(IImport, { 7 | type: 'style', 8 | contentType: 'css', 9 | registerScope: fn_doNothing 10 | }); -------------------------------------------------------------------------------- /src/feature/modules/Import/ImportText.ts: -------------------------------------------------------------------------------- 1 | import { i_Types } from './ImportTypes'; 2 | import { class_create } from '@utils/class'; 3 | import { ImportScript } from './ImportScript'; 4 | 5 | export const ImportText = i_Types['text'] = class_create(ImportScript, { 6 | type: 'text', 7 | contentType: 'txt' 8 | }); -------------------------------------------------------------------------------- /src/feature/modules/Import/ImportTypes.ts: -------------------------------------------------------------------------------- 1 | export const i_Types = {} -------------------------------------------------------------------------------- /src/feature/modules/Import/exports.ts: -------------------------------------------------------------------------------- 1 | import './ImportData' 2 | import './ImportMask' 3 | import './ImportHtml' 4 | import './ImportScript' 5 | import './ImportStyle' 6 | import './ImportText' 7 | 8 | export { i_createImport } from './utils' -------------------------------------------------------------------------------- /src/feature/modules/Import/utils.ts: -------------------------------------------------------------------------------- 1 | import { u_resolvePathFromImport } from '../utils'; 2 | import { Endpoint } from '../class/Endpoint'; 3 | import { i_Types } from './ImportTypes' 4 | import { type_get } from '../types'; 5 | 6 | 7 | export function i_createImport (node, ctx, ctr, module?) { 8 | var path = u_resolvePathFromImport(node, ctx, ctr, module), 9 | endpoint = new Endpoint(path, node.contentType, node.moduleType); 10 | return create(endpoint, node, module); 11 | }; 12 | 13 | 14 | function create (endpoint, node, parent){ 15 | return new (Factory(endpoint))(endpoint, node, parent); 16 | }; 17 | 18 | function Factory(endpoint) { 19 | var type = type_get(endpoint); 20 | var Ctor = i_Types[type]; 21 | if (Ctor == null) { 22 | throw Error('Module is not supported for type ' + type + ' and the path ' + endpoint.path); 23 | } 24 | return Ctor; 25 | } -------------------------------------------------------------------------------- /src/feature/modules/Module/ModuleData.ts: -------------------------------------------------------------------------------- 1 | import { m_Types } from './ModuleTypes'; 2 | import { class_create } from '@utils/class'; 3 | import { ModuleScript } from './ModuleScript'; 4 | import { _file_getJson } from '../loaders'; 5 | 6 | export const ModuleData = m_Types['data'] = class_create(ModuleScript, { 7 | type: 'data', 8 | 9 | load_: _file_getJson 10 | }); -------------------------------------------------------------------------------- /src/feature/modules/Module/ModuleHtml.ts: -------------------------------------------------------------------------------- 1 | import { class_create } from '@utils/class'; 2 | import { parser_parseHtml } from '@core/parser/exports'; 3 | import { m_Types } from './ModuleTypes'; 4 | import { ModuleMask } from './ModuleMask'; 5 | 6 | 7 | export const ModuleHtml = m_Types['html'] = class_create(ModuleMask, { 8 | type: 'mask', 9 | preprocess_ (mix, next) { 10 | var ast = typeof mix === 'string' 11 | ? parser_parseHtml(mix) 12 | : mix 13 | ; 14 | return ModuleMask 15 | .prototype 16 | .preprocess_ 17 | .call(this, ast, next); 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /src/feature/modules/Module/ModuleScript.ts: -------------------------------------------------------------------------------- 1 | import { IModule } from './Module'; 2 | import { m_Types } from './ModuleTypes'; 3 | import { class_create } from '@utils/class'; 4 | import { _file_getScript } from '../loaders'; 5 | import { log_error } from '@core/util/reporters'; 6 | import { _opts } from '../Opts'; 7 | 8 | export const ModuleScript = m_Types['script'] = class_create(IModule, { 9 | type: 'script', 10 | load_: _file_getScript, 11 | preprocessError_: function(error, next) { 12 | log_error('Resource ' + this.path + ' thrown an Exception: ' + error); 13 | next(error); 14 | }, 15 | getExport: function(property) { 16 | var fn = IModule.prototype.getExport; 17 | var obj = fn.call(this, property); 18 | if (obj == null && _opts.es6Modules) { 19 | return fn.call(this, 'default'); 20 | } 21 | return obj; 22 | } 23 | }); -------------------------------------------------------------------------------- /src/feature/modules/Module/ModuleStyle.ts: -------------------------------------------------------------------------------- 1 | import { IModule } from './Module'; 2 | import { m_Types } from './ModuleTypes'; 3 | import { class_create } from '@utils/class'; 4 | import { _file_getStyle } from '../loaders'; 5 | 6 | export const ModuleStyle = m_Types['style'] = class_create(IModule, { 7 | type: 'style', 8 | load_: _file_getStyle 9 | }); -------------------------------------------------------------------------------- /src/feature/modules/Module/ModuleText.ts: -------------------------------------------------------------------------------- 1 | import { m_Types } from './ModuleTypes'; 2 | import { ModuleScript } from './ModuleScript'; 3 | import { class_create } from '@utils/class'; 4 | import { _file_get } from '../loaders'; 5 | 6 | export const ModuleText = m_Types['text'] = class_create(ModuleScript, { 7 | type: 'text', 8 | load_: _file_get, 9 | getExport: function(property) { 10 | return this.exports; 11 | } 12 | }); -------------------------------------------------------------------------------- /src/feature/modules/Module/ModuleTypes.ts: -------------------------------------------------------------------------------- 1 | export const m_Types = {}; -------------------------------------------------------------------------------- /src/feature/modules/Module/exports.ts: -------------------------------------------------------------------------------- 1 | import './ModuleData' 2 | import './ModuleMask' 3 | import './ModuleHtml' 4 | import './ModuleScript' 5 | import './ModuleStyle' 6 | import './ModuleText' 7 | import './register' 8 | 9 | export { 10 | m_createModule, 11 | m_registerModule, 12 | m_registerModuleType 13 | } from './utils' -------------------------------------------------------------------------------- /src/feature/modules/Module/register.ts: -------------------------------------------------------------------------------- 1 | import { ModuleMidd } from '@core/arch/Module' 2 | import { class_Dfr } from '@utils/class/Dfr'; 3 | import { ModuleMask } from './ModuleMask'; 4 | 5 | ModuleMidd.parseMaskContent = function (mix: string | any, path: string): PromiseLike<{ [key: string]: any }> { 6 | return class_Dfr.run((resolve, reject) => { 7 | new ModuleMask(path || '').preprocess_(mix, function( 8 | error, 9 | exports 10 | ) { 11 | if (error) { 12 | reject(error); 13 | return; 14 | } 15 | resolve(exports); 16 | }); 17 | 18 | }); 19 | } -------------------------------------------------------------------------------- /src/feature/modules/Opts.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const _opts = { 4 | base: null, 5 | nsBase: '/', 6 | version: null, 7 | es6Modules: false, 8 | moduleResolution: 'classic', 9 | ext: { 10 | 'mask': 'mask', 11 | 'script': 'js', 12 | 'style': 'js' 13 | }, 14 | prefixes: {} 15 | }; -------------------------------------------------------------------------------- /src/feature/modules/cache.ts: -------------------------------------------------------------------------------- 1 | import { obj_extend } from '@utils/obj'; 2 | import { type_getModuleType } from './types'; 3 | import { Endpoint } from './class/Endpoint'; 4 | 5 | var _cache = {}; 6 | 7 | export function cache_get (endpoint: Endpoint) { 8 | return ensure(endpoint)[endpoint.path]; 9 | }; 10 | export function cache_set (endpoint: Endpoint, module) { 11 | return (ensure(endpoint)[endpoint.path] = module); 12 | }; 13 | export function cache_clear (path?) { 14 | if (path == null) { 15 | _cache = {}; 16 | return; 17 | } 18 | for (var x in _cache) { 19 | delete _cache[x][path]; 20 | } 21 | }; 22 | export function cache_toMap () { 23 | var out = {}; 24 | for (var x in _cache) { 25 | obj_extend(out, _cache[x]); 26 | } 27 | return out; 28 | }; 29 | function ensure (endpoint) { 30 | var type = type_getModuleType(endpoint); 31 | var hash = _cache[type]; 32 | if (hash == null) { 33 | hash = _cache[type] = {}; 34 | } 35 | return hash; 36 | } 37 | -------------------------------------------------------------------------------- /src/feature/modules/class/Endpoint.ts: -------------------------------------------------------------------------------- 1 | export class Endpoint { 2 | path: string 3 | contentType: string 4 | moduleType: string 5 | 6 | constructor (path, contentType?, moduleType?) { 7 | this.path = path; 8 | this.contentType = contentType; 9 | this.moduleType = moduleType; 10 | } 11 | } -------------------------------------------------------------------------------- /src/feature/modules/config.ts: -------------------------------------------------------------------------------- 1 | import { _opts } from './Opts'; 2 | import { obj_getProperty } from '@utils/obj'; 3 | import { is_String, is_Object } from '@utils/is'; 4 | import { u_setOption } from './utils'; 5 | 6 | export function m_cfg(mix, val?){ 7 | if (arguments.length === 1) { 8 | if (is_String(mix)) { 9 | return obj_getProperty(_opts, mix); 10 | } 11 | if (is_Object(mix)) { 12 | for (var key in mix) { 13 | u_setOption(_opts, key, mix[key]); 14 | } 15 | } 16 | return this; 17 | } 18 | u_setOption(_opts, mix, val); 19 | return this; 20 | }; -------------------------------------------------------------------------------- /src/feature/modules/utils/mask-module.ts: -------------------------------------------------------------------------------- 1 | import { Dom } from '@core/dom/exports'; 2 | 3 | // Also flattern all `imports` tags 4 | export function mask_nodesToArray(mix) { 5 | var type = mix.type; 6 | if (type === Dom.NODE && mix.tagName === 'imports') { 7 | return mix.nodes; 8 | } 9 | if (type !== Dom.FRAGMENT && type != null) { 10 | return [mix]; 11 | } 12 | var arr = mix; 13 | if (type === Dom.FRAGMENT) { 14 | arr = mix.nodes; 15 | if (arr == null) { 16 | return []; 17 | } 18 | } 19 | var imax = arr.length, 20 | i = -1, 21 | x; 22 | while (++i < imax) { 23 | x = arr[i]; 24 | if (x.tagName === 'imports') { 25 | arr.splice.apply(arr, [i, 1].concat(x.nodes)); 26 | i--; 27 | } 28 | } 29 | 30 | return arr; 31 | } -------------------------------------------------------------------------------- /src/feature/optimize.ts: -------------------------------------------------------------------------------- 1 | import { mask_TreeWalker } from './TreeWalker'; 2 | import { custom_Optimizers } from '@core/custom/exports'; 3 | 4 | /** 5 | * Run all registerd optimizers recursively on the nodes 6 | * @param {MaskNode} node 7 | * @param {function} onComplete 8 | * @param {mask.optimize~onComplete} done 9 | */ 10 | export function mask_optimize (dom, done) { 11 | mask_TreeWalker.walkAsync( 12 | dom 13 | , function (node, next) { 14 | var fn = getOptimizer(node); 15 | if (fn != null) { 16 | fn(node, next); 17 | return; 18 | } 19 | next(); 20 | } 21 | , done 22 | ); 23 | }; 24 | 25 | /** 26 | * Register custom optimizer for a node name 27 | * @param {string} tagName - Node name 28 | * @param {function} visitor - Used for @see {@link mask.TreeWalker.walkSync} 29 | */ 30 | export function mask_registerOptimizer (tagName, fn){ 31 | custom_Optimizers[tagName] = fn; 32 | }; 33 | 34 | function getOptimizer(node) { 35 | return custom_Optimizers[node.tagName]; 36 | } 37 | 38 | /** 39 | * Returns optimized mask tree 40 | * @callback mask.optimize~onComplete 41 | * @param {MaskNode} node 42 | */ 43 | -------------------------------------------------------------------------------- /src/handlers/debug.ts: -------------------------------------------------------------------------------- 1 | import { custom_Statements } from '@core/custom/exports'; 2 | import { expression_evalStatements } from '@project/expression/src/exports'; 3 | import { customTag_register } from '@core/custom/exports'; 4 | 5 | 6 | custom_Statements['log'] = { 7 | render (node, model, ctx, container, controller) { 8 | var arr = expression_evalStatements(node.expression, model, ctx, controller); 9 | arr.unshift('Mask::Log'); 10 | console.log.apply(console, arr); 11 | } 12 | }; 13 | customTag_register('debugger', { 14 | render (model, ctx, container, compo) { 15 | debugger; 16 | } 17 | }); 18 | customTag_register(':utest', class { 19 | $: JQuery 20 | render (model, ctx, container) { 21 | if (container.nodeType === Node.DOCUMENT_FRAGMENT_NODE) 22 | container = container.childNodes; 23 | this.$ = $(container); 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /src/handlers/define.ts: -------------------------------------------------------------------------------- 1 | import { custom_Tags } from '@core/custom/exports'; 2 | import { class_create } from '@utils/class'; 3 | import { Define } from '@core/feature/Define'; 4 | import { fn_doNothing } from '@utils/fn'; 5 | 6 | custom_Tags['define'] = class_create({ 7 | meta: { 8 | serializeNodes: true 9 | }, 10 | constructor: function(node, model, ctx, el, ctr) { 11 | Define.registerGlobal(node, model, ctr); 12 | }, 13 | render: fn_doNothing 14 | }); 15 | 16 | custom_Tags['let'] = class_create({ 17 | meta: { 18 | serializeNodes: true 19 | }, 20 | constructor: function(node, model, ctx, el, ctr) { 21 | Define.registerScoped(node, model, ctr); 22 | }, 23 | render: fn_doNothing 24 | }); 25 | -------------------------------------------------------------------------------- /src/handlers/exports.ts: -------------------------------------------------------------------------------- 1 | import './debug' 2 | import './define' 3 | import './html' 4 | import './content' 5 | import './var' 6 | import './svg' 7 | 8 | export { Templates } from './template' -------------------------------------------------------------------------------- /src/handlers/html.ts: -------------------------------------------------------------------------------- 1 | import { jMask } from '@mask-j/jMask'; 2 | import { customTag_register } from '@core/custom/exports'; 3 | 4 | 5 | var Compo = { 6 | meta: { 7 | mode: 'server:all' 8 | }, 9 | render: function(model, ctx, container) { 10 | this.html = jMask(this.nodes).text(model, ctx, this); 11 | 12 | if (container.insertAdjacentHTML) { 13 | container.insertAdjacentHTML('beforeend', this.html); 14 | return; 15 | } 16 | if (container.ownerDocument) { 17 | var div = document.createElement('div'), 18 | child; 19 | div.innerHTML = this.html; 20 | child = div.firstChild; 21 | while (child != null) { 22 | container.appendChild(child); 23 | child = child.nextSibling; 24 | } 25 | } 26 | }, 27 | toHtml: function(){ 28 | return this.html || ''; 29 | }, 30 | html: null 31 | }; 32 | customTag_register(':html', Compo); 33 | -------------------------------------------------------------------------------- /src/handlers/svg.ts: -------------------------------------------------------------------------------- 1 | import { builder_buildSVG } from '@core/builder/exports'; 2 | import { customTag_register } from '@core/custom/exports'; 3 | 4 | 5 | var Compo = { 6 | meta: { 7 | mode: 'server:all' 8 | }, 9 | render: function(model, ctx, container, ctr, children) { 10 | var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); 11 | for (var key in this.attr) { 12 | svg.setAttribute(key, this.attr[key]); 13 | } 14 | 15 | builder_buildSVG(this.nodes, model, ctx, svg, ctr, children); 16 | 17 | container.appendChild(svg); 18 | }, 19 | }; 20 | customTag_register('svg', Compo); 21 | -------------------------------------------------------------------------------- /src/handlers/var.ts: -------------------------------------------------------------------------------- 1 | import { custom_Tags, customTag_Base } from '@core/custom/exports'; 2 | import { class_create } from '@utils/class'; 3 | import { expression_eval } from '@project/expression/src/exports'; 4 | 5 | (function(){ 6 | // TODO: refactor methods, use MaskNode Serialization instead Model Serialization 7 | custom_Tags['var'] = class_create(customTag_Base, { 8 | renderStart: function(model, ctx){ 9 | set(this, this.attr, true, model, ctx); 10 | }, 11 | onRenderStartClient: function(){ 12 | set(this, this.model, false) 13 | } 14 | }); 15 | 16 | function set(self, source, doEval, model?, ctx?) { 17 | // set data also to model, so that it will be serialized in NodeJS 18 | self.model = {}; 19 | 20 | var parent = self.parent; 21 | var scope = parent.scope; 22 | if (scope == null) { 23 | scope = parent.scope = {}; 24 | } 25 | for(var key in source){ 26 | self.model[key] = scope[key] = doEval === false 27 | ? source[key] 28 | : expression_eval(source[key], model, ctx, parent); 29 | } 30 | } 31 | }()); -------------------------------------------------------------------------------- /src/parser/ParserAst.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atmajs/MaskJS/f3951546aa9b5ada57fe66a35e7fa4809108f6c2/src/parser/ParserAst.ts -------------------------------------------------------------------------------- /src/parser/Templates.ts: -------------------------------------------------------------------------------- 1 | import { _Object_hasOwnProp } from '@utils/refs'; 2 | import { parser_parse } from './mask/parser'; 3 | 4 | export const Templates = { 5 | ensure (mix: string | any, ctx: { filename?: string }) { 6 | if (typeof mix !== 'string') { 7 | return mix; 8 | } 9 | if (_Object_hasOwnProp.call(_cache, mix)){ 10 | /* if Object doesnt contains property that check is faster 11 | then "!=null" http://jsperf.com/not-in-vs-null/2 */ 12 | return _cache[mix]; 13 | } 14 | return _cache[mix] = parser_parse(mix, ctx.filename); 15 | } 16 | } 17 | var _cache = {}; 18 | -------------------------------------------------------------------------------- /src/parser/config.ts: -------------------------------------------------------------------------------- 1 | export const parser_cfg_ContentTags = { 2 | script: 1, 3 | style: 1, 4 | template: 1, 5 | markdown: 1 6 | }; 7 | 8 | export function parser_defineContentTag (name){ 9 | parser_cfg_ContentTags[name] = 1; 10 | }; 11 | -------------------------------------------------------------------------------- /src/parser/const.ts: -------------------------------------------------------------------------------- 1 | import { log_error } from '@core/util/reporters'; 2 | 3 | export var interp_START = '~'; 4 | export var interp_OPEN = '['; 5 | export var interp_CLOSE = ']'; 6 | 7 | // ~ 8 | export var interp_code_START = 126; 9 | // [ 10 | export var interp_code_OPEN = 91; 11 | // ] 12 | export var interp_code_CLOSE = 93; 13 | 14 | export var go_tag = 10; 15 | export var go_up = 11; 16 | export var go_attrVal = 12; 17 | export var go_propVal = 13; 18 | export var go_attrHeadVal = 14; 19 | 20 | export var state_tag = 3; 21 | export var state_attr = 4; 22 | export var state_prop = 5; 23 | export var state_literal = 6; 24 | 25 | export function parser_setInterpolationQuotes (start, end) { 26 | if (!start || start.length !== 2) { 27 | log_error('Interpolation Start must contain 2 Characters'); 28 | return; 29 | } 30 | if (!end || end.length !== 1) { 31 | log_error('Interpolation End must be of 1 Character'); 32 | return; 33 | } 34 | 35 | interp_code_START = start.charCodeAt(0); 36 | interp_code_OPEN = start.charCodeAt(1); 37 | interp_code_CLOSE = end.charCodeAt(0); 38 | 39 | interp_START = start[0]; 40 | interp_OPEN = start[1]; 41 | interp_CLOSE = end; 42 | }; 43 | -------------------------------------------------------------------------------- /src/parser/exports.ts: -------------------------------------------------------------------------------- 1 | export { parser_parse } from './mask/parser' 2 | export { parser_parseHtml } from './html/parser' 3 | export { parser_parseAttr, parser_parseAttrObject } from './mask/partials/attributes'; 4 | export { parser_parseLiteral} from './mask/partials/literal'; 5 | export { parser_setInterpolationQuotes } from './const' 6 | export { parser_ensureTemplateFunction } from './interpolation'; 7 | export { parser_cleanObject } from './utils'; 8 | export { parser_ObjectLexer } from './object/ObjectLexer'; 9 | export { parser_defineContentTag} from './config'; 10 | export { mask_stringify, mask_stringifyAttr} from './mask/stringify'; 11 | export { Templates } from './Templates' 12 | export { cursor_groupEnd } from './cursor' 13 | 14 | import './parsers/content' 15 | import './parsers/define' 16 | import './parsers/import' 17 | import './parsers/var' 18 | -------------------------------------------------------------------------------- /src/parser/object/consume.ts: -------------------------------------------------------------------------------- 1 | import { parser_error } from '@core/util/reporters'; 2 | 3 | export function _consume (tokens, str, index, length, out, isOptional){ 4 | var index_ = index; 5 | var imax = tokens.length, 6 | i = 0, token, start; 7 | for(; i < imax; i++) { 8 | token = tokens[i]; 9 | start = index; 10 | index = token.consume(str, index, length, out); 11 | if (index === start) { 12 | if (token.optional === true) { 13 | continue; 14 | } 15 | if (isOptional === true) { 16 | return index_; 17 | } 18 | // global require is also not optional: throw error 19 | var msg = 'Token of type `' + token.name + '`'; 20 | if (token.token) { 21 | msg += ' Did you mean: `' + token.token + '`?'; 22 | } 23 | parser_error(msg, str, index); 24 | return index_; 25 | } 26 | } 27 | return index; 28 | }; 29 | -------------------------------------------------------------------------------- /src/parser/parsers/IImportNode.ts: -------------------------------------------------------------------------------- 1 | import { INode } from '@core/dom/INode'; 2 | 3 | export interface IImportNode extends INode{ 4 | contentType: string 5 | moduleType: string 6 | namespace: string 7 | exports: IImportEntry[] 8 | alias: string 9 | async: string 10 | path: string 11 | link: string 12 | mode: string 13 | } 14 | 15 | export interface IImportEntry { 16 | name: string 17 | alias?: string 18 | } -------------------------------------------------------------------------------- /src/parser/parsers/content/style.ts: -------------------------------------------------------------------------------- 1 | import { parser_ensureTemplateFunction } from '../../interpolation'; 2 | 3 | export const Style = { 4 | transform: function(body, attr, parent) { 5 | if (attr.self != null) { 6 | var style = parent.attr.style; 7 | parent.attr.style = parser_ensureTemplateFunction((style || '') + body); 8 | return null; 9 | } 10 | return body; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /src/parser/utils.ts: -------------------------------------------------------------------------------- 1 | import { is_Array } from '@utils/is'; 2 | 3 | export function parser_cleanObject (mix) { 4 | if (is_Array(mix)) { 5 | for (var i = 0; i < mix.length; i++) { 6 | parser_cleanObject(mix[i]); 7 | } 8 | return mix; 9 | } 10 | delete mix.parent; 11 | delete mix.__single; 12 | if (mix.nodes != null) { 13 | parser_cleanObject(mix.nodes); 14 | } 15 | return mix; 16 | }; -------------------------------------------------------------------------------- /src/scope-vars.ts: -------------------------------------------------------------------------------- 1 | export const __rgxEscapedChar = { 2 | "'": /\\'/g, 3 | '"': /\\"/g, 4 | '{': /\\\{/g, 5 | '>': /\\>/g, 6 | ';': /\\>/g 7 | }; -------------------------------------------------------------------------------- /src/statements/exports.ts: -------------------------------------------------------------------------------- 1 | import './if' 2 | import './for' 3 | import './each' 4 | import './with' 5 | import './switch' 6 | import './visible' 7 | import './repeat' -------------------------------------------------------------------------------- /src/statements/utils.ts: -------------------------------------------------------------------------------- 1 | import { is_ArrayLike } from '@utils/is'; 2 | import { _document } from '@utils/refs'; 3 | 4 | export function els_toggleVisibility (mix, state) { 5 | if (mix == null) { 6 | return; 7 | } 8 | if (is_ArrayLike(mix)) { 9 | _toggleArr(mix, state); 10 | return; 11 | } 12 | _toggle(mix, state); 13 | }; 14 | function _toggle(el, state) { 15 | el.style.display = state ? '' : 'none'; 16 | } 17 | function _toggleArr(els, state) { 18 | var imax = els.length, 19 | i = -1; 20 | while (++i < imax) _toggle(els[i], state); 21 | } 22 | 23 | 24 | export function el_renderPlaceholder (container) { 25 | let anchor = _document.createComment(''); 26 | container.appendChild(anchor); 27 | return anchor; 28 | } -------------------------------------------------------------------------------- /src/statements/visible.ts: -------------------------------------------------------------------------------- 1 | import { custom_Statements } from '@core/custom/exports'; 2 | import { expression_eval } from '@project/expression/src/exports'; 3 | import { builder_build } from '@core/builder/exports'; 4 | import { arr_pushMany } from '@utils/arr'; 5 | 6 | custom_Statements['visible'] = { 7 | toggle: toggle, 8 | render: function(node, model, ctx, container, ctr, children){ 9 | var els = []; 10 | builder_build(node.nodes, model, ctx, container, ctr, els); 11 | arr_pushMany(children, els) 12 | 13 | var visible = expression_eval(node.expression, model, ctx, ctr); 14 | toggle(els, visible); 15 | } 16 | }; 17 | function toggle(els, visible){ 18 | for(var i = 0; i < els.length; i++){ 19 | els[i].style.display = visible ? '' : 'none'; 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/statements/with.ts: -------------------------------------------------------------------------------- 1 | import { custom_Statements } from '@core/custom/exports'; 2 | import { expression_eval } from '@project/expression/src/exports'; 3 | import { builder_build } from '@core/builder/exports'; 4 | import { warn_withNode } from '@core/util/reporters'; 5 | 6 | custom_Statements['with'] = { 7 | render: function(node, model, ctx, el, ctr, elements){ 8 | var obj = expression_eval( 9 | node.expression 10 | , model 11 | , ctx 12 | , ctr 13 | ); 14 | if (obj == null) { 15 | warn_withNode('Value is undefined', node); 16 | } 17 | builder_build( 18 | node.nodes 19 | , obj 20 | , ctx 21 | , el 22 | , ctr 23 | , elements 24 | ); 25 | } 26 | }; -------------------------------------------------------------------------------- /src/types/Parameters.ts: -------------------------------------------------------------------------------- 1 | export type ParametersFromSecond any> = 2 | T extends (x, ...args: infer P) => any ? P : never; 3 | -------------------------------------------------------------------------------- /src/types/types-ts.ts: -------------------------------------------------------------------------------- 1 | 2 | export type MethodKeys = { 3 | [P in keyof T]: T[P] extends (...args) => any ? P : never; 4 | }[keyof T]; 5 | 6 | class WrappedArray extends Array { 7 | 8 | } 9 | 10 | export type ArrayMethods = MethodKeys 11 | -------------------------------------------------------------------------------- /src/umd-wrapper.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MaskJS v%IMPORT(version)% 3 | * Part of the Atma.js Project 4 | * http://atmajs.com/ 5 | * 6 | * MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | * (c) 2012, %IMPORT(year)% Atma.js and other contributors 10 | */ 11 | (function (root, factory) { 12 | 'use strict'; 13 | 14 | var _env = (typeof window === 'undefined' || window.navigator == null) 15 | ? 'node' 16 | : 'dom'; 17 | var _global = (_env === 'dom') 18 | ? window 19 | : global; 20 | var _isCommonJs = typeof exports !== 'undefined' 21 | && (root == null || root === exports || root === _global); 22 | if (_isCommonJs) { 23 | root = exports; 24 | } 25 | var _exports = root || _global; 26 | var _document = _global.document; 27 | 28 | function construct(){ 29 | var mask = factory(_global, _exports, _document); 30 | if (_isCommonJs) { 31 | module.exports = mask; 32 | } 33 | return mask; 34 | } 35 | 36 | if (typeof define === 'function' && define.amd) { 37 | return define(construct); 38 | } 39 | 40 | // Browser OR Node 41 | return construct(); 42 | 43 | }(this, function (global, exports, document) { 44 | 'use strict'; 45 | 46 | /**MODULE**/ 47 | 48 | return (exports.mask = Mask); 49 | })); -------------------------------------------------------------------------------- /src/util/array.ts: -------------------------------------------------------------------------------- 1 | 2 | // export function arr_pushMany (arr, arrSource){ 3 | // if (arrSource == null || arr == null) 4 | // return; 5 | 6 | // var il = arr.length, 7 | // jl = arrSource.length, 8 | // j = -1 9 | // ; 10 | // while( ++j < jl ){ 11 | // arr[il + j] = arrSource[j]; 12 | // } 13 | // }; 14 | -------------------------------------------------------------------------------- /src/util/attr.ts: -------------------------------------------------------------------------------- 1 | import { obj_create } from '@utils/obj'; 2 | 3 | export function attr_extend(a, b) { 4 | if (a == null) { 5 | return b == null ? {} : obj_create(b); 6 | } 7 | if (b == null) { 8 | return a; 9 | } 10 | for (let key in b) { 11 | if ('class' === key && typeof a[key] === 'string') { 12 | a[key] += ' ' + b[key]; 13 | continue; 14 | } 15 | a[key] = b[key]; 16 | } 17 | return a; 18 | }; 19 | export function attr_first(attr) { 20 | for (var key in attr) return key; 21 | return null; 22 | }; 23 | -------------------------------------------------------------------------------- /src/util/compo.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@compo/exports'; 2 | import { builder_build } from '@core/builder/exports'; 3 | import { is_Array } from '@utils/is'; 4 | import { _document } from '@utils/refs'; 5 | 6 | export function compo_addChild(ctr, compo) { 7 | compo_addChildren(ctr, compo); 8 | }; 9 | export function compo_addChildren(ctr, ...compos) { 10 | let arr = ctr.components; 11 | if (arr == null) { 12 | ctr.components = compos; 13 | return; 14 | } 15 | arr.push(...compos); 16 | }; 17 | 18 | export function compo_renderElements (nodes, model, ctx, el, ctr, children?){ 19 | if (nodes == null){ 20 | return null; 21 | } 22 | const arr = []; 23 | builder_build(nodes, model, ctx, el, ctr, arr); 24 | if (is_Array(children)) { 25 | children.push(...arr); 26 | } 27 | return arr; 28 | }; 29 | 30 | export function compo_emitInserted (ctr) { 31 | Component.signal.emitIn(ctr, 'domInsert'); 32 | }; 33 | 34 | export function compo_renderPlaceholder(staticCompo, compo, container) { 35 | var placeholder = staticCompo.placeholder; 36 | if (placeholder == null) { 37 | placeholder = _document.createComment(''); 38 | container.appendChild(placeholder); 39 | } 40 | compo.placeholder = placeholder; 41 | }; -------------------------------------------------------------------------------- /src/util/dom.ts: -------------------------------------------------------------------------------- 1 | import { arr_each } from '@utils/arr'; 2 | 3 | function setVisibility (state, el) { 4 | if (el != null) { 5 | el.style.display = state ? '' : 'none'; 6 | } 7 | } 8 | 9 | export function dom_remove (el) { 10 | var parent = el.parentNode; 11 | if (parent == null) { 12 | return el; 13 | } 14 | return parent.removeChild(el); 15 | }; 16 | export function dom_removeAll (arr) { 17 | arr_each(arr, dom_remove); 18 | }; 19 | export const dom_show = setVisibility.bind(null, true); 20 | export const dom_hide = setVisibility.bind(null, false); 21 | 22 | 23 | export function dom_showAll (arr) { 24 | arr_each(arr, dom_show); 25 | } 26 | export function dom_hideAll (arr) { 27 | arr_each(arr, dom_hide); 28 | } 29 | 30 | 31 | export function dom_insertAfter (el, anchor) { 32 | return anchor.parentNode.insertBefore(el, anchor.nextSibling); 33 | }; 34 | export function dom_insertBefore (el, anchor) { 35 | return anchor.parentNode.insertBefore(el, anchor); 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /src/util/exports.ts: -------------------------------------------------------------------------------- 1 | // import ./util.js 2 | // import ./attr.js 3 | // import ./array.js 4 | // import ./object.js 5 | // import ./listeners.js 6 | // import ./reporters.js 7 | // import ./path.js 8 | // import ./resource/file.js 9 | // import ./css.js -------------------------------------------------------------------------------- /src/util/listeners.ts: -------------------------------------------------------------------------------- 1 | import { arr_remove } from '@utils/arr'; 2 | 3 | /** 4 | * Bind listeners to some system events: 5 | * - `error` Any parser or render error 6 | * - `compoCreated` Each time new component is created 7 | * - `config` Each time configuration is changed via `config` fn 8 | * @param {string} eveny 9 | * @param {function} cb 10 | * @memberOf mask 11 | * @method on 12 | */ 13 | export function listeners_on(event, fn) { 14 | (bin[event] || (bin[event] = [])).push(fn); 15 | } 16 | /** 17 | * Unbind listener 18 | * - `error` Any parser or render error 19 | * - `compoCreated` Each time new component is created 20 | * @param {string} eveny 21 | * @param {function} [cb] 22 | * @memberOf mask 23 | * @method on 24 | */ 25 | export function listeners_off(event, fn?) { 26 | if (fn == null) { 27 | bin[event] = []; 28 | return; 29 | } 30 | arr_remove(bin[event], fn); 31 | } 32 | export function listeners_emit(event, v1?, v2?, v3?, v4?, v5?) { 33 | var fns = bin[event]; 34 | if (fns == null) { 35 | return false; 36 | } 37 | var imax = fns.length, 38 | i = -1; 39 | while (++i < imax) { 40 | fns[i](v1, v2, v3, v4, v5); 41 | } 42 | return i !== 0; 43 | } 44 | 45 | const bin = { 46 | compoCreated: null, 47 | error: null 48 | }; 49 | -------------------------------------------------------------------------------- /src/util/resource/file.ts: -------------------------------------------------------------------------------- 1 | import { xhr_get, script_get, style_get } from './transports/xhr_base'; 2 | import { json_get } from './transports/json'; 3 | import { path_resolveUrl } from '../path'; 4 | import { class_Dfr } from '@utils/class/Dfr'; 5 | import { Module } from '@core/feature/modules/exports'; 6 | 7 | export function file_get(path, ctr) { 8 | return get(xhr_get, path, ctr); 9 | } 10 | export function file_getScript(path, ctr) { 11 | return get(script_get, path, ctr); 12 | } 13 | export function file_getStyle(path, ctr) { 14 | return get(style_get, path, ctr); 15 | } 16 | export function file_getJson(path, ctr) { 17 | return get(json_get, path, ctr); 18 | } 19 | 20 | function get(fn, path, ctr) { 21 | let url = path_resolveUrl(path, Module.resolveLocation(ctr)); 22 | if (url in Cache) { 23 | return Cache[url]; 24 | } 25 | const dfr = Cache[url] = new class_Dfr(); 26 | fn(url, dfr.pipeCallback()); 27 | return dfr; 28 | } 29 | 30 | const Cache = Object.create(null); 31 | -------------------------------------------------------------------------------- /src/util/resource/transports/json.ts: -------------------------------------------------------------------------------- 1 | import { xhr_get } from './xhr_base'; 2 | 3 | export function json_get (path, cb){ 4 | xhr_get(path, function(error, str){ 5 | if (error) { 6 | cb(error); 7 | return; 8 | } 9 | var json; 10 | try { 11 | json = JSON.parse(str); 12 | } catch (error) { 13 | cb('JSON error: ' + String(error)); 14 | return; 15 | } 16 | cb(null, json); 17 | }) 18 | }; 19 | -------------------------------------------------------------------------------- /src/util/resource/transports/script_node.ts: -------------------------------------------------------------------------------- 1 | import { path_toLocalFile } from '@core/util/path'; 2 | 3 | declare var require; 4 | 5 | export function script_get (path, cb){ 6 | var filename = path_toLocalFile(path); 7 | try { 8 | var x = require(filename); 9 | cb(null, x); 10 | } catch (error) { 11 | cb(error); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/util/resource/transports/style_browser.ts: -------------------------------------------------------------------------------- 1 | 2 | export function style_get (path, cb){ 3 | embedStyle(path); 4 | // do not wait for the load event 5 | cb(); 6 | }; 7 | 8 | 9 | 10 | export function embedStyle (url, callback?) { 11 | var tag = document.createElement('link'); 12 | tag.rel = 'stylesheet'; 13 | tag.href = url; 14 | if ('onreadystatechange' in tag) { 15 | (tag as any).onreadystatechange = function() { 16 | (this.readyState === 'complete' || this.readyState === 'loaded') && callback(); 17 | }; 18 | } else { 19 | tag.onload = tag.onerror = callback; 20 | } 21 | if (_head === void 0) { 22 | _head = document.getElementsByTagName('head')[0]; 23 | } 24 | _head.appendChild(tag); 25 | }; 26 | var _head; 27 | -------------------------------------------------------------------------------- /src/util/resource/transports/style_node.ts: -------------------------------------------------------------------------------- 1 | 2 | export function style_get (path, cb){ 3 | // skip all CSS embeddings 4 | cb(); 5 | }; 6 | -------------------------------------------------------------------------------- /src/util/resource/transports/xhr_base.ts: -------------------------------------------------------------------------------- 1 | //#if (BROWSER) 2 | export { xhr_get } from './xhr_browser' 3 | export { style_get } from './style_browser' 4 | export { script_get } from './script_browser' 5 | //#endif 6 | 7 | /*#if (NODE) 8 | export { xhr_get } from './xhr_node' 9 | export { style_get } from './style_node' 10 | export { script_get } from './script_node' 11 | */ 12 | -------------------------------------------------------------------------------- /src/util/resource/transports/xhr_browser.ts: -------------------------------------------------------------------------------- 1 | 2 | export function xhr_get (path, cb){ 3 | var xhr = new XMLHttpRequest(); 4 | xhr.onreadystatechange = function() { 5 | if (xhr.readyState !== 4) 6 | return; 7 | 8 | var res = xhr.responseText, 9 | status = xhr.status, 10 | err, errMsg; 11 | if (status !== 0 && status !== 200) { 12 | errMsg = res || xhr.statusText; 13 | } 14 | if (status === 0 && res === '') { 15 | errMsg = res || xhr.statusText || 'File is not accessible'; 16 | } 17 | if (errMsg != null) { 18 | err = { 19 | status: status, 20 | content: errMsg 21 | }; 22 | } 23 | cb(err, res); 24 | }; 25 | xhr.open('GET', path, true); 26 | xhr.send(); 27 | }; 28 | -------------------------------------------------------------------------------- /src/util/resource/transports/xhr_node.ts: -------------------------------------------------------------------------------- 1 | import { path_toLocalFile } from '@core/util/path'; 2 | declare var require; 3 | 4 | export function xhr_get(path, cb) { 5 | //@TODO Implement remote http getter 6 | 7 | var filename = path_toLocalFile(path); 8 | fs.readFile(filename, 'utf8', function(error, str) { 9 | if (error != null) { 10 | cb({ 11 | message: error.toString(), 12 | status: error.code 13 | }); 14 | return; 15 | } 16 | cb(null, str); 17 | }); 18 | } 19 | 20 | var fs = require('fs'); 21 | -------------------------------------------------------------------------------- /test/benchmark/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "maskjs-0.52.4": "https://github.com/atmajs/MaskJS/tarball/v0.52.4", 4 | "maskjs-0.12.23": "https://github.com/atmajs/MaskJS/tarball/v0.12.23" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/benchmark/bower_components/maskjs-0.12.23/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "maskjs", 3 | "version": "0.12.23", 4 | "homepage": "https://github.com/atmajs/MaskJS", 5 | "authors": [ 6 | "Alex Kit " 7 | ], 8 | "description": "Template / Markup / HMVC Engine", 9 | "main": "lib/mask.js", 10 | "keywords": [ 11 | "MVC", 12 | "Components" 13 | ], 14 | "license": "MIT", 15 | "ignore": [ 16 | ".travis.yml", 17 | "build.js", 18 | "*.komodoproject", 19 | "builds/", 20 | "src/", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ], 26 | "_release": "0.12.23", 27 | "_resolution": { 28 | "type": "version", 29 | "tag": "v0.12.23", 30 | "commit": "45c3bf60d67ded592bd9a1126fdfba31d0f64606" 31 | }, 32 | "_source": "https://github.com/atmajs/MaskJS.git", 33 | "_target": "0.12.23", 34 | "_originalSource": "https://github.com/atmajs/MaskJS.git" 35 | } -------------------------------------------------------------------------------- /test/benchmark/bower_components/maskjs-0.12.23/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "maskjs", 3 | "version": "0.12.23", 4 | "homepage": "https://github.com/atmajs/MaskJS", 5 | "authors": [ 6 | "Alex Kit " 7 | ], 8 | "description": "Template / Markup / HMVC Engine", 9 | "main": "lib/mask.js", 10 | "keywords": [ 11 | "MVC", 12 | "Components" 13 | ], 14 | "license": "MIT", 15 | "ignore": [ 16 | ".travis.yml", 17 | "build.js", 18 | "*.komodoproject", 19 | "builds/", 20 | "src/", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ] 26 | } -------------------------------------------------------------------------------- /test/benchmark/bower_components/maskjs-0.52.4/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "maskjs", 3 | "version": "0.52.4", 4 | "homepage": "https://github.com/atmajs/MaskJS", 5 | "authors": [ 6 | "Alex Kit " 7 | ], 8 | "description": "Template / Markup / HMVC Engine", 9 | "main": "lib/mask.js", 10 | "keywords": [ 11 | "MVC", 12 | "Components" 13 | ], 14 | "license": "MIT", 15 | "ignore": [ 16 | ".travis.yml", 17 | "build.js", 18 | "*.komodoproject", 19 | "builds/", 20 | "src/", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ], 26 | "_release": "0.52.4", 27 | "_resolution": { 28 | "type": "version", 29 | "tag": "v0.52.4", 30 | "commit": "1b2f8823ee0f3f423e2cc269113e39f8e708248e" 31 | }, 32 | "_source": "https://github.com/atmajs/MaskJS.git", 33 | "_target": "0.52.4", 34 | "_originalSource": "https://github.com/atmajs/MaskJS.git" 35 | } -------------------------------------------------------------------------------- /test/benchmark/bower_components/maskjs-0.52.4/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "maskjs", 3 | "version": "0.52.4", 4 | "homepage": "https://github.com/atmajs/MaskJS", 5 | "authors": [ 6 | "Alex Kit " 7 | ], 8 | "description": "Template / Markup / HMVC Engine", 9 | "main": "lib/mask.js", 10 | "keywords": [ 11 | "MVC", 12 | "Components" 13 | ], 14 | "license": "MIT", 15 | "ignore": [ 16 | ".travis.yml", 17 | "build.js", 18 | "*.komodoproject", 19 | "builds/", 20 | "src/", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ] 26 | } -------------------------------------------------------------------------------- /test/benchmark/define.test: -------------------------------------------------------------------------------- 1 | UTest.benchmarkVersions({ 2 | $config: { 3 | versions: { 4 | '0.52.4' : '/test/benchmark/bower_components/maskjs-0.52.4/lib/mask.js', 5 | 'latest' : '/lib/mask.js' 6 | } 7 | }, 8 | 'should benchmark compo initialization and rendering via define tag': { 9 | '0.52.4' (mask) { 10 | createElements(mask); 11 | }, 12 | 'latest' (mask) { 13 | createElements(mask); 14 | } 15 | } 16 | }); 17 | 18 | function createElements(mask) { 19 | var template = ` 20 | define Foo { 21 | 22 | var count = 0; 23 | function onRenderStart () { 24 | this.scope.count++; 25 | } 26 | function foo () { 27 | return 'foo'; 28 | } 29 | slot name1 () { 30 | return false; 31 | } 32 | slot name2 () { 33 | return false; 34 | } 35 | 36 | h4 > '~[$.foo()]' 37 | } 38 | 39 | Foo; 40 | `; 41 | var dom = mask.render(mask.parse(template)); 42 | } -------------------------------------------------------------------------------- /test/benchmark/eval.test: -------------------------------------------------------------------------------- 1 | var exec = eval; 2 | UTest.benchmark({ 3 | 'evaluating': { 4 | 'create function: raw' () { 5 | var code = ` 6 | return [ 7 | function onRenderStart () { 8 | return foo + '!${Date.now()}!' 9 | } 10 | ]; 11 | 12 | `; 13 | var factory = Function('foo', code); 14 | var fns = factory('Foo'); 15 | var fn = fns[0]; 16 | var result = fn(); 17 | }, 18 | 19 | 'create function' () { 20 | var code = ` 21 | return function (foo) { 22 | return [ 23 | function onRenderStart () { 24 | return foo + '!${Date.now()}!' 25 | } 26 | ] 27 | } 28 | `; 29 | var wrapper = Function(code); 30 | var factory = wrapper(); 31 | var fns = factory('Foo'); 32 | var fn = fns[0]; 33 | var result = fn(); 34 | }, 35 | 36 | 'evaluate code' () { 37 | var code = ` 38 | (function (foo) { 39 | return [ 40 | function onRenderStart () { 41 | return foo + '!${Date.now()}!' 42 | } 43 | ] 44 | }) 45 | `; 46 | var factory = exec.call(null, code); 47 | var fns = factory('Foo'); 48 | var fn = fns[0]; 49 | var result = fn(); 50 | } 51 | } 52 | }) -------------------------------------------------------------------------------- /test/benchmark/render.test: -------------------------------------------------------------------------------- 1 | UTest.benchmarkVersions({ 2 | $config: { 3 | versions: { 4 | '0.12.23' : '/test/benchmark/bower_components/maskjs-0.12.23/lib/mask.js', 5 | '0.52.4' : '/test/benchmark/bower_components/maskjs-0.52.4/lib/mask.js', 6 | 'latest' : '/lib/mask.js' 7 | } 8 | }, 9 | 'should benchmark element rendering': { 10 | '0.12.23' (mask) { 11 | createElements(mask); 12 | }, 13 | '0.52.4' (mask) { 14 | createElements(mask); 15 | }, 16 | 'latest' (mask) { 17 | createElements(mask); 18 | } 19 | } 20 | }); 21 | 22 | function createElements(mask) { 23 | var count = 100, tags = ['div', 'span', 'section', 'b'], arr = []; 24 | while(--count) { 25 | arr = arr.concat(tags); 26 | } 27 | mask.render(arr.join(';')); 28 | } -------------------------------------------------------------------------------- /test/dom/async.spec.ts: -------------------------------------------------------------------------------- 1 | import { customTag_register } from '@core/custom/exports' 2 | import { parser_parse } from '@core/parser/exports' 3 | import { Compo } from '@compo/exports' 4 | import { $render } from './utils' 5 | 6 | 7 | UTest({ 8 | 'async - core'(done){ 9 | 10 | var cb; 11 | customTag_register('Foo', class { 12 | 13 | nodes = parser_parse('#defer > "foo"') 14 | async = true 15 | await (callback){ 16 | cb = callback; 17 | } 18 | renderStart(){ 19 | setTimeout(() => cb(), 200); 20 | } 21 | }); 22 | 23 | var $ = $render('h4 > Foo;'); 24 | $.hasNot_('#defer'); 25 | 26 | setTimeout(function(){ 27 | $.has_('#defer'); 28 | done(); 29 | }, 300); 30 | }, 31 | 'async - compo'(done){ 32 | 33 | customTag_register('Foo', Compo({ 34 | template: '.defer > "foo"', 35 | onRenderStart(model, ctx){ 36 | 37 | var resume = Compo.pause(this, ctx); 38 | setTimeout(resume, 200); 39 | } 40 | })); 41 | 42 | var $ = $render('.c > Foo;') 43 | .has_('.c') 44 | .hasNot_('.defer'); 45 | 46 | 47 | setTimeout(function(){ 48 | 49 | $.has_('.defer'); 50 | done(); 51 | }, 300); 52 | }, 53 | 54 | }); 55 | -------------------------------------------------------------------------------- /test/dom/feature/define-methods.spec.ts: -------------------------------------------------------------------------------- 1 | import { customTag_define } from '@core/custom/exports' 2 | import { Compo } from '@compo/exports' 3 | import '@core/feature/methods/exports' 4 | import '@core/feature/modules/exports' 5 | 6 | declare var sinon; 7 | 8 | UTest({ 9 | 'slot should be private (do not pass the signal to parent)' () { 10 | var parentFn = sinon.spy(); 11 | customTag_define('FooParent', Compo({ 12 | slots: { 13 | test: parentFn 14 | } 15 | })); 16 | customTag_define(` 17 | define Foo { 18 | 19 | var called = false; 20 | 21 | slot private test () { 22 | this.scope.called = true; 23 | } 24 | 25 | button x-click=test; 26 | } 27 | `); 28 | 29 | var compo = Compo.initialize('FooParent > Foo'); 30 | return UTest 31 | .domtest(compo.$, ` 32 | find(button) > click; 33 | `) 34 | .then(() => { 35 | var foo = compo.find('Foo'); 36 | eq_(foo.scope.called, true); 37 | eq_(parentFn.callCount, 0); 38 | }); 39 | } 40 | }) -------------------------------------------------------------------------------- /test/dom/feature/optimize.spec.ts: -------------------------------------------------------------------------------- 1 | import { mask_optimize, mask_registerOptimizer } from '@core/feature/optimize'; 2 | import { parser_parse } from '@core/parser/exports'; 3 | import { jMask } from '@mask-j/jMask'; 4 | 5 | UTest({ 6 | 'should change text' (done) { 7 | 8 | mask_registerOptimizer('foo', function(node, next){ 9 | node.nodes = parser_parse("'Foo'"); 10 | next({ deep: false }); 11 | }); 12 | 13 | var frag = parser_parse('div; foo > "Bar"'); 14 | var txt = jMask(frag).filter('foo').text(); 15 | 16 | eq_(txt, 'Bar'); 17 | mask_optimize(frag, assert.await(function(frag){ 18 | txt = jMask(frag).filter('foo').text(); 19 | eq_(txt, 'Foo'); 20 | done(); 21 | })); 22 | }, 23 | 'should replace node' (done) { 24 | mask_registerOptimizer('baz', function(node, next){ 25 | var node = parser_parse('span > "Baz"'); 26 | next({ replace: node }); 27 | }); 28 | 29 | var frag = parser_parse('div; baz > "Bar"'); 30 | var txt = jMask(frag).filter('baz').text(); 31 | eq_(txt, 'Bar'); 32 | 33 | mask_optimize(frag, assert.await(function(frag){ 34 | 35 | var baz = jMask(frag).filter('baz'); 36 | eq_(baz.length, 0); 37 | 38 | txt = jMask(frag).filter('span').text(); 39 | eq_(txt, 'Baz'); 40 | done(); 41 | })); 42 | } 43 | }) 44 | -------------------------------------------------------------------------------- /test/dom/handler/include.spec.ts: -------------------------------------------------------------------------------- 1 | import { Compo } from '@compo/exports'; 2 | 3 | UTest({ 4 | 'should include template without defining a component' () { 5 | var template = ` 6 | define TestInclude { 7 | div > @foo; 8 | } 9 | 10 | include TestInclude { 11 | @foo > span; 12 | } 13 | `; 14 | 15 | var compo = Compo.initialize(template); 16 | 17 | eq_(compo.components.length, 1); 18 | eq_(compo.components[0].compoName, 'define'); 19 | compo 20 | .$ 21 | .has_('div > span'); 22 | } 23 | }); 24 | 25 | -------------------------------------------------------------------------------- /test/dom/interpolations.spec.ts: -------------------------------------------------------------------------------- 1 | import { customTag_define } from '@core/custom/exports' 2 | import { Compo } from '@compo/exports' 3 | 4 | UTest({ 5 | 'attributes': { 6 | 'components' : { 7 | 'should use parent as `this` in expressions' () { 8 | customTag_define('Foo', Compo({ 9 | myNum: 5 10 | })); 11 | customTag_define('Bar', Compo({ 12 | myNum: 7 13 | })); 14 | var compo = Compo.initialize('Bar > Foo test=~[this.myNum] > div test="~[this.myNum]"'); 15 | var foo = compo.find('Foo'); 16 | is_(foo.attr.test, 'Number'); 17 | eq_(foo.attr.test, 7); 18 | 19 | var divAttrVal = compo.$.filter('div').attr('test'); 20 | is_(divAttrVal, 'String'); 21 | eq_(divAttrVal, '5'); 22 | } 23 | } 24 | } 25 | }) -------------------------------------------------------------------------------- /test/dom/modules/custom.spec.ts: -------------------------------------------------------------------------------- 1 | import { renderer_renderAsync } from '@core/renderer/exports'; 2 | import { Module } from '@core/feature/modules/exports' 3 | 4 | UTest({ 5 | async 'Should load module' () { 6 | Module.registerModuleType('data', 'myJson', { 7 | async load_ () { 8 | return { foo: 'fox' }; 9 | } 10 | }) 11 | var template = ` 12 | import * as Test from 'any' as myJson; 13 | 14 | h4 > '~Test.foo' 15 | `; 16 | 17 | var dom = await renderer_renderAsync(template); 18 | 19 | await UTest.domtest(dom, ` 20 | find ('h4') > text fox; 21 | `) 22 | } 23 | }) -------------------------------------------------------------------------------- /test/dom/modules/npm.spec.ts: -------------------------------------------------------------------------------- 1 | import { mask_config } from '@core/api/config'; 2 | import { Module } from '@core/feature/modules/exports'; 3 | import { renderer_renderAsync } from '@core/renderer/exports'; 4 | import { listeners_on, listeners_off } from '@core/util/listeners'; 5 | 6 | UTest({ 7 | $before () { 8 | // use default module loader 9 | mask_config('modules', 'default'); 10 | Module.cfg('moduleResolution', 'node'); 11 | }, 12 | $after () { 13 | Module.cfg('moduleResolution', 'classic'); 14 | listeners_off('error'); 15 | }, 16 | 17 | async 'should load default file in node_modules' () { 18 | let dom = await renderer_renderAsync(` 19 | import Foo from '/test/tmpl/npm/foo.mask'; 20 | 21 | Foo; 22 | `); 23 | 24 | return UTest.domtest(dom, ` 25 | find ('h4') > text ('EmptyPackage'); 26 | `); 27 | }, 28 | async 'should fail loading' () { 29 | var errors = []; 30 | 31 | listeners_on('error', assert.await((error) => errors.push(error))); 32 | await renderer_renderAsync(` 33 | import Any from '/test/tmpl/npm/foo-none.mask'; 34 | Any; 35 | `); 36 | 37 | notEq_(errors.length, 0); 38 | var error = errors[0]; 39 | has_(error.message, 'Module was not resolved'); 40 | } 41 | }); 42 | 43 | -------------------------------------------------------------------------------- /test/dom/node/pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { renderer_render } from '@core/renderer/exports'; 2 | import { customTag_get } from '@core/custom/tag'; 3 | 4 | UTest({ 5 | 'pipe test' () { 6 | var template = ` 7 | define Foo { 8 | pipe bazzinga::qux (event) { 9 | $(event.currentTarget).text('Two'); 10 | } 11 | button x-pipe-signal='click: bazzinga.qux' > 'One' 12 | } 13 | Foo; 14 | `; 15 | 16 | var dom = renderer_render(template); 17 | is_(customTag_get('Foo').prototype.pipes.bazzinga.qux, 'Function'); 18 | 19 | return UTest.domtest(dom, ` 20 | find ('button') { 21 | text One; 22 | click; 23 | text Two; 24 | call remove; 25 | } 26 | `); 27 | }, 28 | 29 | }) 30 | 31 | -------------------------------------------------------------------------------- /test/dom/node/properties.spec.ts: -------------------------------------------------------------------------------- 1 | import { customTag_define } from '@core/custom/tag'; 2 | import { renderer_render } from '@core/renderer/exports'; 3 | import { Compo } from '@compo/exports'; 4 | 5 | declare var sinon; 6 | 7 | UTest({ 8 | 'should set elements property' () { 9 | 10 | let div = renderer_render(` 11 | div 12 | [style.position] = relative 13 | [style.borderTopWidth] = 2em 14 | ; 15 | `); 16 | eq_(div.style.position, 'relative'); 17 | eq_(div.style.borderTopWidth, '2em'); 18 | }, 19 | 'should set components properties' () { 20 | let fn = sinon.spy(function(model){ 21 | eq_(this.a.b.c, 'd'); 22 | }); 23 | customTag_define('Foo', Compo({ 24 | onRenderStart: fn 25 | })) 26 | 27 | renderer_render('Foo [a.b.c] = d'); 28 | eq_(fn.callCount, 1); 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /test/dom/node/slot_event.spec.ts: -------------------------------------------------------------------------------- 1 | import { renderer_render } from '@core/renderer/exports'; 2 | 3 | UTest({ 4 | 'slot test' () { 5 | var template = ` 6 | define Foo {} 7 | section { 8 | Foo { 9 | slot fooTest (event) { 10 | $(event.currentTarget).text('Baz'); 11 | } 12 | 13 | button x-signal='click: fooTest' > 'Foo' 14 | } 15 | } 16 | `; 17 | 18 | var dom = renderer_render(template); 19 | return UTest.domtest(dom, ` 20 | find ('button') { 21 | text Foo; 22 | click; 23 | text Baz; 24 | call remove; 25 | } 26 | `); 27 | }, 28 | 29 | 'event test' () { 30 | var template = ` 31 | section { 32 | button { 33 | event click (event) { 34 | event.target.textContent = 'Baz' 35 | } 36 | 'Foo' 37 | } 38 | } 39 | `; 40 | var dom = renderer_render(template); 41 | return UTest.domtest(dom, ` 42 | find ('button') { 43 | text Foo; 44 | click; 45 | text Baz; 46 | call remove; 47 | } 48 | `); 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /test/dom/parsers/html.spec.ts: -------------------------------------------------------------------------------- 1 | import { renderer_render } from '@core/renderer/exports'; 2 | 3 | UTest({ 4 | 'mixed markup' () { 5 | var template = ` 6 |
7 |

i>'Foo'

8 |
9 | `; 10 | var dom = renderer_render(template); 11 | return UTest.domtest(dom, ` 12 | find('section>h4>i') > 13 | text Foo; 14 | `); 15 | }, 16 | 'html markup' () { 17 | var template = `
    18 |
  • Foo
  • 19 |
  • Bar
  • 20 |
21 | 22 | 23 |

Lorem ipsum doler it semet

24 | `; 25 | var dom = renderer_render(template); 26 | return UTest.domtest(dom, ` 27 | find('ul > li') { 28 | length 2; 29 | } 30 | filter ('input') { 31 | length 2; 32 | eq (0) > attr name foo-input; 33 | eq (1) > attr name baz-input; 34 | } 35 | filter ('h4') > text ('Lorem ipsum doler it semet'); 36 | `); 37 | } 38 | 39 | }) -------------------------------------------------------------------------------- /test/dom/parsers/var.spec.ts: -------------------------------------------------------------------------------- 1 | import { parser_parse } from '@core/parser/exports'; 2 | 3 | UTest({ 4 | 'parsing attributes to expression string': { 5 | 'should parse number' () { 6 | var template = `var a = 2`; 7 | var node = parser_parse(template); 8 | eq_(node.attr.a, '2'); 9 | }, 10 | 'should parse string' () { 11 | var template = `var myVar_isBest = "foo's"`; 12 | var node = parser_parse(template); 13 | eq_(node.attr.myVar_isBest, `"foo's"`); 14 | }, 15 | 'should parse multiple declarations' () { 16 | var template = `var foo = x, baz=5;`; 17 | var node = parser_parse(template); 18 | eq_(node.attr.foo, 'x'); 19 | eq_(node.attr.baz, '5'); 20 | }, 21 | 'should parse object' () { 22 | var template = `var var = {a:1}`; 23 | var node = parser_parse(template); 24 | eq_(node.attr.var, `{a:1}`); 25 | }, 26 | 'should parse function call' () { 27 | var template = `var var = this.getFoo(a,b,'string');`; 28 | var node = parser_parse(template); 29 | eq_(node.attr.var, `this.getFoo(a,b,'string')`); 30 | }, 31 | } 32 | }); -------------------------------------------------------------------------------- /test/dom/svg/render.spec.ts: -------------------------------------------------------------------------------- 1 | import { renderer_render } from '@core/renderer/exports'; 2 | 3 | UTest({ 4 | 'render svg' () { 5 | var frag = renderer_render(` 6 | svg { 7 | rect width=100 height=100; 8 | } 9 | `); 10 | 11 | var rect = $(frag).find('rect').get(0); 12 | eq_('rx' in rect, true); 13 | } 14 | }) -------------------------------------------------------------------------------- /test/examples/component-async.spec.ts: -------------------------------------------------------------------------------- 1 | UTest({ 2 | 'should render async component': function(done){ 3 | 4 | UTest 5 | .server 6 | .request('/examples/component-async.html') 7 | .done(function(doc, win){ 8 | 9 | setTimeout(function(){ 10 | $(doc.body) 11 | .find('input') 12 | .eq_('length', 1) 13 | .eq_('val', 'Tom') 14 | ; 15 | 16 | done(); 17 | }, 800); 18 | }); 19 | } 20 | }); -------------------------------------------------------------------------------- /test/examples/import.spec.ts: -------------------------------------------------------------------------------- 1 | UTest({ 2 | 'should imported components': function(done){ 3 | 4 | return UTest 5 | .server 6 | .request({ 7 | url: '/examples/import.html', 8 | data: { base: '/utest/examples/' } 9 | }) 10 | .pipe(function(doc, win){ 11 | 12 | return UTest.domtest(doc.body, ` 13 | with ('.panel') { 14 | length 2; 15 | 16 | eq (0) { 17 | find ('.body') > is (':visible'); 18 | find ('h4') { 19 | has ('text', 'Foo title'); 20 | do click; 21 | } 22 | find ('.body') > isNot (':visible'); 23 | } 24 | eq (1) { 25 | find ('.body') > is (':visible'); 26 | 27 | find ('button') > do click; 28 | find ('i') > text 1; 29 | find ('button') > do click; 30 | find ('i') > text 2; 31 | 32 | find('h4') { 33 | has ('text', 'Counter Panel'); 34 | do click; 35 | } 36 | find ('.body') > isNot (':visible'); 37 | } 38 | } 39 | `); 40 | 41 | }); 42 | } 43 | }); -------------------------------------------------------------------------------- /test/examples/simple.spec.ts: -------------------------------------------------------------------------------- 1 | UTest({ 2 | 'should render flower list': function(done){ 3 | 4 | return UTest 5 | .server 6 | .request('/examples/simple.html') 7 | .done(function(doc, win){ 8 | 9 | $(doc.body) 10 | .find('ul') 11 | .eq_('length', 1) 12 | .has_('html', '>Sunflower') 13 | ; 14 | }); 15 | } 16 | }); -------------------------------------------------------------------------------- /test/node/parser/decorators.spec.ts: -------------------------------------------------------------------------------- 1 | import { parser_parse, mask_stringify } from '@core/parser/exports'; 2 | import { Dom } from '@core/dom/exports'; 3 | 4 | UTest({ 5 | 'should parse and serialize method' () { 6 | 7 | var ast = parser_parse(` 8 | [Colorize] 9 | div; 10 | `); 11 | 12 | var nodes = ast.nodes; 13 | eq_(nodes.length, 2); 14 | 15 | eq_(nodes[0].expression, 'Colorize'); 16 | eq_(nodes[0].type, Dom.DECORATOR); 17 | 18 | eq_(nodes[1].tagName, 'div'); 19 | eq_(nodes[1].type, Dom.NODE); 20 | 21 | '> serialize' 22 | 23 | var str = mask_stringify(ast); 24 | eq_(str, '[Colorize]div;') 25 | }, 26 | 'should parse multiple decorators' () { 27 | var template = ` 28 | 29 | [RedBackground] 30 | [GreenColor] 31 | div > 'Hello'; 32 | `; 33 | var ast = parser_parse(template); 34 | var nodes = ast.nodes; 35 | eq_(nodes.length, 3); 36 | 37 | eq_(nodes[0].expression, 'RedBackground'); 38 | eq_(nodes[0].type, Dom.DECORATOR); 39 | eq_(nodes[1].expression, 'GreenColor'); 40 | eq_(nodes[1].type, Dom.DECORATOR); 41 | 42 | eq_(nodes[2].tagName, 'div'); 43 | eq_(nodes[2].type, Dom.NODE); 44 | 45 | '> serialize' 46 | 47 | var str = mask_stringify(ast); 48 | eq_(str, `[RedBackground][GreenColor]div>'Hello'`) 49 | } 50 | }) -------------------------------------------------------------------------------- /test/node/parser/script.spec.ts: -------------------------------------------------------------------------------- 1 | import { parser_parse } from '@core/parser/exports'; 2 | import { jMask } from '@mask-j/jMask'; 3 | 4 | UTest({ 5 | 'content':{ 6 | 'block' () { 7 | var template = `script {"A"}`; 8 | var node = parser_parse(template); 9 | eq_(node.content, '"A"'); 10 | }, 11 | 'nodes' () { 12 | var template = `script > :html {"A"}`; 13 | var node = parser_parse(template); 14 | eq_(node.nodes[0].tagName, ':html'); 15 | var txt = jMask(node).text(); 16 | eq_(txt, 'A'); 17 | }, 18 | }, 19 | 'attribute' : { 20 | 'block' () { 21 | var template = `script type='text/mask' {"A"}`; 22 | var node = parser_parse(template); 23 | eq_(node.content, '"A"'); 24 | eq_(node.attr.type, 'text/mask'); 25 | }, 26 | 'literal' () { 27 | var template = `script type='text/mask' > ''baz`; 28 | var nodes = parser_parse(template).nodes; 29 | eq_(nodes[0].content, ''); 30 | eq_(nodes[0].attr.type, 'text/mask'); 31 | 32 | eq_(nodes[1].tagName, 'baz'); 33 | } 34 | } 35 | }) 36 | 37 | // vim: set ft=js: -------------------------------------------------------------------------------- /test/node/stringify-nodes.spec.ts: -------------------------------------------------------------------------------- 1 | import { mask_stringify, parser_parse } from '@core/parser/exports'; 2 | 3 | UTest({ 4 | 'should stringify head' () { 5 | var str = 'span.head@[attr.type]-sub;'; 6 | eq_(str, mask_stringify(parser_parse(str))); 7 | 8 | var str = 'span.head~[bind: attr.type ]-sub ._isVisible .yo .~[ testy ] ;'; 9 | eq_(mask_stringify(parser_parse(str)), 'span.head~[bind: attr.type ]-sub._isVisible.yo.~[ testy ];'); 10 | }, 11 | 'should stringify empty attribute values' () { 12 | let str = mask_stringify(parser_parse('div foo="" bar="1"')); 13 | 14 | eq_(str, "div foo='' bar=1;"); 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /test/tmpl/a.mask: -------------------------------------------------------------------------------- 1 | h4 .a > 'a' -------------------------------------------------------------------------------- /test/tmpl/modules/ImmediateInvokeDefine.mask: -------------------------------------------------------------------------------- 1 | let Greetings { 2 | span > 'Hello' 3 | } 4 | 5 | define IidSample { 6 | h4 > Greetings; 7 | } 8 | 9 | IidSample; -------------------------------------------------------------------------------- /test/tmpl/modules/baz.ini: -------------------------------------------------------------------------------- 1 | name=Baz -------------------------------------------------------------------------------- /test/tmpl/modules/baz.txt: -------------------------------------------------------------------------------- 1 | Hello foo baz! -------------------------------------------------------------------------------- /test/tmpl/modules/data_baz.json: -------------------------------------------------------------------------------- 1 | { 2 | "baz": { 3 | "name": "Baz" 4 | } 5 | } -------------------------------------------------------------------------------- /test/tmpl/modules/data_foo.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | foo: { 3 | name: 'Foo' 4 | } 5 | }; -------------------------------------------------------------------------------- /test/tmpl/modules/data_foo_1.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | foo: { 3 | name: 'Foo1' 4 | } 5 | }; -------------------------------------------------------------------------------- /test/tmpl/modules/data_foo_2.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | foo: { 3 | name: 'Foo2' 4 | } 5 | }; -------------------------------------------------------------------------------- /test/tmpl/modules/data_foo_3.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | foo: { 3 | name: 'Foo3' 4 | } 5 | }; -------------------------------------------------------------------------------- /test/tmpl/modules/data_service.js: -------------------------------------------------------------------------------- 1 | module.exports = function Service () { 2 | 3 | this.getData = function () { 4 | return 'iFoo'; 5 | }; 6 | }; -------------------------------------------------------------------------------- /test/tmpl/modules/defines.mask: -------------------------------------------------------------------------------- 1 | 'Tester' 2 | 3 | define :menu { 4 | menu > li > 'Home' 5 | } 6 | 7 | define :footer { 8 | footer > span > 'Copyright' 9 | } -------------------------------------------------------------------------------- /test/tmpl/modules/defines_scopes.mask: -------------------------------------------------------------------------------- 1 | import :footer as Footer, :menu as Menu from './defines'; 2 | 3 | define FooScoped { 4 | 5 | let BazInner { 6 | h6.inner > 'Inner'; 7 | :menu; 8 | } 9 | 10 | BazInner; 11 | :footer; 12 | } -------------------------------------------------------------------------------- /test/tmpl/modules/ext-less/myinfo: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myinfo" 3 | } -------------------------------------------------------------------------------- /test/tmpl/modules/ext-less/mymeta: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | meta: { 3 | name: 'mymeta' 4 | } 5 | }; -------------------------------------------------------------------------------- /test/tmpl/modules/ext-less/view: -------------------------------------------------------------------------------- 1 | define View { 2 | h4.view; 3 | } -------------------------------------------------------------------------------- /test/tmpl/modules/h4.mask: -------------------------------------------------------------------------------- 1 | h4 > 'a' -------------------------------------------------------------------------------- /test/tmpl/modules/header_content.mask: -------------------------------------------------------------------------------- 1 | header > 'Header' 2 | .content > 'content' -------------------------------------------------------------------------------- /test/tmpl/modules/html/header.html: -------------------------------------------------------------------------------- 1 |
Foo
-------------------------------------------------------------------------------- /test/tmpl/modules/model.mask: -------------------------------------------------------------------------------- 1 | div.test-above-node; 2 | 3 | import foo from 'data_foo.js'; 4 | import baz from 'data_baz.json'; 5 | import * as title from './h4'; 6 | import from 'style.css'; 7 | 8 | 9 | with (foo) { 10 | title; 11 | .foo > '~[name]' 12 | } 13 | 14 | .baz > '~[baz.name]'; -------------------------------------------------------------------------------- /test/tmpl/modules/nest-a.mask: -------------------------------------------------------------------------------- 1 | import h4 as b_nest from './nest-b'; 2 | 3 | section .a { 4 | b_nest; 5 | } -------------------------------------------------------------------------------- /test/tmpl/modules/nest-b.mask: -------------------------------------------------------------------------------- 1 | h4 .b { 2 | 'B Module' 3 | } -------------------------------------------------------------------------------- /test/tmpl/modules/nest.mask: -------------------------------------------------------------------------------- 1 | import * as a_nest from './nest-a'; 2 | import * as SubFolder from '../a'; 3 | 4 | div > a_nest; 5 | 6 | SubFolder; -------------------------------------------------------------------------------- /test/tmpl/modules/package.mask: -------------------------------------------------------------------------------- 1 | module path='a.mask' { 2 | h4 > '~[name]' 3 | } 4 | 5 | import * as :test from './a.mask'; 6 | p > :test; -------------------------------------------------------------------------------- /test/tmpl/modules/route_resolver.mask: -------------------------------------------------------------------------------- 1 | import:route ('templates', '/test/tmpl/{0}.mask') 2 | import * as Data from 'templates: a' -------------------------------------------------------------------------------- /test/tmpl/modules/static.mask: -------------------------------------------------------------------------------- 1 | define FooStatics { 2 | 3 | function static transform (str) { 4 | return str.toUpperCase(); 5 | } 6 | } -------------------------------------------------------------------------------- /test/tmpl/modules/style.css: -------------------------------------------------------------------------------- 1 | .foo { 2 | background: red; 3 | } -------------------------------------------------------------------------------- /test/tmpl/modules/versioned.mask: -------------------------------------------------------------------------------- 1 | section > 'Baz' -------------------------------------------------------------------------------- /test/tmpl/npm/foo-none.mask: -------------------------------------------------------------------------------- 1 | import NotExists from 'fake'; 2 | 3 | define Any { 4 | NotExists; 5 | } 6 | -------------------------------------------------------------------------------- /test/tmpl/npm/foo.mask: -------------------------------------------------------------------------------- 1 | import * as Header from 'foo-module' is mask; 2 | 3 | define Foo { 4 | Header; 5 | } -------------------------------------------------------------------------------- /test/tmpl/npm/node_modules/foo-module/index.mask: -------------------------------------------------------------------------------- 1 | h4 > 'EmptyPackage' -------------------------------------------------------------------------------- /test/tmpl/npm/node_modules/foo-module/package.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /test/tmpl/stringify/content.mask: -------------------------------------------------------------------------------- 1 | div { 2 | script disabled { 3 | var a = 10; 4 | } 5 | } 6 | ---- 7 | div { 8 | script disabled { 9 | 10 | var a = 10; 11 | 12 | } 13 | } 14 | ================= 15 | div { 16 | style scoped{ 17 | span {} 18 | } 19 | } 20 | ---- 21 | div { 22 | style scoped { 23 | 24 | span {} 25 | 26 | } 27 | } 28 | ================= 29 | define foo { 30 | slot change(event) { 31 | var a = 10; 32 | } 33 | } 34 | ----- 35 | define foo { 36 | slot change (event) { 37 | 38 | var a = 10; 39 | 40 | } 41 | } 42 | ================= 43 | var pages = [ '1', '2' ]; 44 | ----- 45 | var pages=[ '1', '2' ]; -------------------------------------------------------------------------------- /test/tmpl/stringify/content.min.mask: -------------------------------------------------------------------------------- 1 | div { 2 | script disabled { 3 | var a = 10; 4 | } 5 | } 6 | ---- 7 | div{script disabled{ 8 | var a = 10; 9 | }} 10 | ================= 11 | div { 12 | style scoped{ 13 | span {} 14 | } 15 | } 16 | ---- 17 | div{style scoped{ 18 | span {} 19 | }} 20 | ================= 21 | define foo { 22 | slot change(event) { 23 | var a = 10; 24 | } 25 | } 26 | ----- 27 | define foo{slot change(event){ 28 | var a = 10; 29 | }} 30 | ================= 31 | var pages = [ '1', '2' ]; 32 | ----- 33 | var pages=[ '1', '2' ]; -------------------------------------------------------------------------------- /test/tmpl/stringify/html.mask: -------------------------------------------------------------------------------- 1 |
Foo
2 | --- 3 |
Foo
4 | 5 | ============================================= 6 | 7 | ul { 8 |
  • A
  • 9 |
  • B
  • 10 | } 11 | --- 12 | ul { 13 |
  • A
  • 14 |
  • B
  • 15 | } 16 | 17 | 18 | ============================================= 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | --- 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ============================================= 37 | define Foo { 38 |
    Foo
    39 | } 40 | --- 41 | define Foo { 42 |
    Foo
    43 | } 44 | 45 | ============================================= 46 |
    47 | 48 | import Foo from 'foo' is json; 49 | 50 |
    51 | --- 52 |
    53 | 54 | import Foo from 'foo' is json; 55 | 56 |
    -------------------------------------------------------------------------------- /test/tmpl/stringify/interpolation.mask: -------------------------------------------------------------------------------- 1 | .~[foo]; 2 | --- 3 | .~[foo]; 4 | === 5 | span .~[foo] .~[baz || quux]; 6 | --- 7 | span.~[foo].~[baz || quux]; 8 | === 9 | span .foo .@[baz]; 10 | --- 11 | span.foo.@[baz]; 12 | === 13 | span .foo .@[attr.baz || attr.qux]; 14 | --- 15 | span.foo.@[attr.baz || attr.qux]; 16 | === -------------------------------------------------------------------------------- /test/tmpl/stringify/literals.mask: -------------------------------------------------------------------------------- 1 | "Lorem ipsum" 2 | --- 3 | 'Lorem ipsum' 4 | 5 | ===================== 6 | 7 | "Lorem \" ipsum" 8 | --- 9 | 'Lorem " ipsum' 10 | 11 | ===================== 12 | 13 | "Lorem ' ipsum" 14 | --- 15 | "Lorem ' ipsum" 16 | 17 | ===================== 18 | 19 | "Lorem ~[bind: foo + baz] ipsum" 20 | --- 21 | 'Lorem ~[bind: foo + baz] ipsum' 22 | 23 | ===================== 24 | 25 | "Lorem ~[bind: 'foo' + 'baz'] ipsum" 26 | --- 27 | "Lorem ~[bind: 'foo' + 'baz'] ipsum" 28 | 29 | ===================== 30 | 31 | "a" 32 | 'b' 33 | "'c'" 34 | --- 35 | 'a' 36 | 'b' 37 | "'c'" 38 | 39 | ===================== 40 | 41 | " 42 | 123456789123456789 43 | " 44 | --- 45 | ' 46 | 123456789123456789 47 | ' 48 | -------------------------------------------------------------------------------- /test/tmpl/stringify/literals.min.mask: -------------------------------------------------------------------------------- 1 | "a" 2 | 'b' 3 | "'c'" 4 | --- 5 | 'a''b'"'c'" -------------------------------------------------------------------------------- /test/tmpl/stringify/misc.mask: -------------------------------------------------------------------------------- 1 | do ("Hello") type 2 | --- 3 | do type ("Hello"); 4 | 5 | ============================================= 6 | 7 | section { 8 | div id='foo' 9 | } 10 | --- 11 | section > 12 | #foo; 13 | 14 | ============================================= 15 | 16 | header { 17 | div .test.baz.~[name]; 18 | span > 'foo' 19 | } 20 | --- 21 | header { 22 | .test.baz.~[name]; 23 | span > 24 | 'foo' 25 | } 26 | 27 | ============================================= 28 | 29 | module path = "foo.mask" { 30 | define foo { 31 | a; 32 | } 33 | }; 34 | import from './foo.mask'; 35 | 36 | import a as X from 'foo'; 37 | a; 38 | 39 | ---------------- 40 | 41 | module path='foo.mask' { 42 | define foo { 43 | a; 44 | } 45 | } 46 | import from './foo.mask'; 47 | import a as X from 'foo'; 48 | a; -------------------------------------------------------------------------------- /test/tmpl/stringify/misc.min.mask: -------------------------------------------------------------------------------- 1 | div { 2 | 'Hello' 3 | } 4 | --- 5 | div>'Hello' 6 | === 7 | div.class name='some' { 8 | div#header > 'Wow ~[name]'; 9 | }; 10 | --- 11 | .class name=some>#header>'Wow ~[name]' 12 | === 13 | span.~[class]#~[id] name='~[: foo.bar + "!"]'; 14 | --- 15 | span#~[id].~[class] name='~[: foo.bar + "!"]'; 16 | === 17 | if (username.indexOf('a') === 0) { 18 | 'admin'; 19 | } 20 | --- 21 | if(username.indexOf('a') === 0)>'admin' 22 | === 23 | div { span; 'Hello' } 24 | --- 25 | div{span;'Hello'} 26 | === 27 | 28 | input checked disabled='disabled' { 29 | :dualbind expression="user.name"; 30 | } 31 | 32 | --- 33 | input checked disabled>:dualbind expression=user.name; 34 | === 35 | module path = "baz.mask" { 36 | define baz { 37 | h4 > "Baz" 38 | } 39 | }; 40 | --- 41 | module path=baz.mask{define baz{h4>'Baz'}} 42 | === 43 | module path = "foo.mask" { 44 | define foo { 45 | a; 46 | } 47 | }; 48 | import from './foo.mask'; 49 | 50 | import a as X from 'foo'; 51 | a; 52 | --- 53 | module path=foo.mask{define foo{a;}}import from './foo.mask';import a as X from 'foo';a; -------------------------------------------------------------------------------- /test/tmpl/stringify/node_head.mask: -------------------------------------------------------------------------------- 1 | div; 2 | --- 3 | div; 4 | 5 | ============================== 6 | 7 | div checked data-id = "id"; 8 | --- 9 | div checked data-id='id'; 10 | 11 | ============================== 12 | 13 | div.foo id = "baz" name='~[bind: foo + "baz"]'; 14 | --- 15 | #baz.foo name='~[bind: foo + "baz"]'; 16 | 17 | ============================== 18 | 19 | section 20 | .foo.~[klass] id ="baz" 21 | name='test ~[name]'; 22 | --- 23 | section#baz.foo.~[klass] name='test ~[name]'; 24 | 25 | 26 | ============================== 27 | 28 | if (test); 29 | --- 30 | if (test); 31 | 32 | ============================== 33 | 34 | +if (test); 35 | --- 36 | +if (test); 37 | 38 | ============================== 39 | 40 | +if (test) x-mode='server'; 41 | --- 42 | +if x-mode='server' (test); 43 | -------------------------------------------------------------------------------- /test/tmpl/stringify/node_head.min.mask: -------------------------------------------------------------------------------- 1 | div checked data-id = "id"; 2 | --- 3 | div checked data-id=id; 4 | 5 | ============================== 6 | 7 | div.foo id = "baz" name='~[bind: foo + "baz"]'; 8 | --- 9 | #baz.foo name='~[bind: foo + "baz"]'; 10 | 11 | ============================== 12 | 13 | section 14 | .foo.~[klass] id ="baz" 15 | name='test ~[name]'; 16 | --- 17 | section#baz.foo.~[klass] name='test ~[name]'; 18 | 19 | 20 | ============================== 21 | 22 | if (test); 23 | --- 24 | if(test); 25 | 26 | ============================== 27 | 28 | +if (test) ; 29 | --- 30 | +if(test); 31 | 32 | ============================== 33 | 34 | +if (test) x-mode='server'; 35 | --- 36 | +if x-mode=server(test); 37 | -------------------------------------------------------------------------------- /test/tmpl/stringify/node_many.mask: -------------------------------------------------------------------------------- 1 | div { 2 | em > 'Foo' 3 | bar > 'Bar' 4 | } 5 | --- 6 | div { 7 | em > 8 | 'Foo' 9 | bar > 10 | 'Bar' 11 | } 12 | 13 | =================================== 14 | 15 | div { 16 | em > 'Foo' 17 | bar > 'Bar' 18 | } 19 | span; section > div { 20 | 'A' 21 | "B" 22 | } 23 | --- 24 | div { 25 | em > 26 | 'Foo' 27 | bar > 28 | 'Bar' 29 | } 30 | span; 31 | section > 32 | div { 33 | 'A' 34 | 'B' 35 | } 36 | 37 | ===================================== 38 | 39 | define foo 40 | as (div.baz) 41 | extends Bar{ 42 | h5 > 'Foo' 43 | } 44 | 45 | ---- 46 | define foo as (div.baz) extends Bar { 47 | h5 > 48 | 'Foo' 49 | } -------------------------------------------------------------------------------- /test/tmpl/stringify/node_many.min.mask: -------------------------------------------------------------------------------- 1 | div { 2 | em > 'Foo' 3 | bar > 'Bar' 4 | } 5 | --- 6 | div{em>'Foo'bar>'Bar'} 7 | 8 | =================================== 9 | 10 | div { 11 | em { 'Foo' } 12 | bar > 'Bar' 13 | } 14 | span; section > div { 15 | 'A' 16 | "B" 17 | } 18 | --- 19 | div{em>'Foo'bar>'Bar'}span;section>div{'A''B'} 20 | 21 | ===================================== -------------------------------------------------------------------------------- /test/tmpl/stringify/node_single.mask: -------------------------------------------------------------------------------- 1 | 2 | div { 'Lorem ipsum doler' }; 3 | --- 4 | div > 5 | 'Lorem ipsum doler' 6 | 7 | ================================== 8 | 9 | ul { 10 | li > span > em > '~[name]' 11 | } 12 | --- 13 | ul > 14 | li > 15 | span > 16 | em > 17 | '~[name]' 18 | 19 | ================================== 20 | 21 | if () { 22 | div > 'Baz' 23 | } 24 | --- 25 | if () > 26 | div > 27 | 'Baz' 28 | -------------------------------------------------------------------------------- /test/tmpl/stringify/node_single.min.mask: -------------------------------------------------------------------------------- 1 | 2 | div { 'Lorem ipsum doler' }; 3 | --- 4 | div>'Lorem ipsum doler' 5 | 6 | ================================== 7 | 8 | ul { 9 | li > span > em > '~[name]' 10 | } 11 | --- 12 | ul>li>span>em>'~[name]' 13 | 14 | ================================== 15 | 16 | if () { 17 | div > 'Baz' 18 | } 19 | --- 20 | if()>div>'Baz' 21 | 22 | ================================== 23 | 24 | div { 'Lorem ipsum doler' }; 25 | span > li; 26 | --- 27 | div>'Lorem ipsum doler'span>li; 28 | 29 | -------------------------------------------------------------------------------- /tsconfig-build-node.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "src/mask.ts" 4 | ], 5 | "exclude": [ 6 | "node_modules" 7 | ], 8 | "compilerOptions": { 9 | "outDir": "ts-temp", 10 | "declaration": true, 11 | "experimentalDecorators": true, 12 | "baseUrl": "./", 13 | "paths": { 14 | "@core/*": [ 15 | "src/*" 16 | ], 17 | "@utils/*": [ 18 | "ref-utils/src/*" 19 | ], 20 | "@mask-j/*": [ 21 | "projects/mask-j/src/jmask/*" 22 | ], 23 | "@compo/*": [ 24 | "projects/mask-compo/src/*" 25 | ], 26 | "@binding/*": [ 27 | "projects/mask-binding/src/*" 28 | ], 29 | "@project/*": [ 30 | "projects/*" 31 | ] 32 | 33 | }, 34 | "module": "commonjs", 35 | "target": "es6" 36 | } 37 | } -------------------------------------------------------------------------------- /tsconfig-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": ["src/mask.ts"], 3 | "exclude": ["node_modules"], 4 | "compilerOptions": { 5 | "outDir": "ts-temp", 6 | "declaration": true, 7 | "experimentalDecorators": true, 8 | "baseUrl": "./", 9 | "paths": { 10 | "@core/*": ["src/*"], 11 | "@utils/*": ["ref-utils/src/*"], 12 | "@mask-j/*": ["projects/mask-j/src/jmask/*"], 13 | "@compo/*": ["projects/mask-compo/src/*"], 14 | "@binding/*": ["projects/mask-binding/src/*"], 15 | "@project/*": ["projects/*"] 16 | }, 17 | "module": "commonjs", 18 | "target": "es6" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": [ 3 | "node_modules", 4 | "ts_temp" 5 | ], 6 | "compilerOptions": { 7 | "experimentalDecorators": true, 8 | "baseUrl": "./", 9 | "paths": { 10 | "@core/*": [ 11 | "src/*" 12 | ], 13 | "@utils/*": [ 14 | "ref-utils/src/*" 15 | ], 16 | "@mask-j/*": [ 17 | "projects/mask-j/src/jmask/*" 18 | ], 19 | "@compo/*": [ 20 | "projects/mask-compo/src/*" 21 | ], 22 | "@binding/*": [ 23 | "projects/mask-binding/src/*" 24 | ], 25 | "@project/*": [ 26 | "projects/*" 27 | ], 28 | "@mask-node/*": [ 29 | "projects/mask-node/src/*" 30 | ] 31 | }, 32 | "module": "es2022" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { Mask } from 'mask'; 4 | 5 | declare global { 6 | const mask: typeof Mask 7 | } 8 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mask", 3 | "main": "types/index.d.ts" 4 | } -------------------------------------------------------------------------------- /typings/globals/assertion/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/atmajs/assertion/master/typings.json", 5 | "raw": "github:atmajs/assertion", 6 | "main": "types/assertion.d.ts", 7 | "global": true, 8 | "name": "assertion" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /typings/globals/atma-utest/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/atmajs/utest/master/typings.json", 5 | "raw": "github:atmajs/utest", 6 | "main": "types/index.d.ts", 7 | "global": true, 8 | "name": "atma-utest" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /typings/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | 5 | interface JQuery { 6 | has_ (selector: string, ...args) 7 | hasNot_ (selector: string, ...args) 8 | eq_ 9 | model (): any 10 | compo (): any 11 | } --------------------------------------------------------------------------------