UNPKG

9.22 kBJavaScriptView Raw
1// Types.
2import { debug } from '../../utils/debug';
3import { isDefined } from '../../utils/types';
4import { sanitizeModuleName } from '../../utils/common';
5import { setPropertyValue, getComponentModule } from './component-builder';
6import { platformNames } from '../../platform';
7import { resolveModuleName } from '../../module-name-resolver';
8import { xml2ui } from './xml2ui';
9export const ios = platformNames.ios.toLowerCase();
10export const android = platformNames.android.toLowerCase();
11export const visionos = platformNames.visionos.toLowerCase();
12export const defaultNameSpaceMatcher = /tns\.xsd$/i;
13export class Builder {
14 static createViewFromEntry(entry) {
15 if (entry.create) {
16 const view = entry.create();
17 if (!view) {
18 throw new Error('Failed to create View with entry.create() function.');
19 }
20 return view;
21 }
22 else if (entry.moduleName) {
23 const moduleName = sanitizeModuleName(entry.moduleName);
24 const resolvedCodeModuleName = resolveModuleName(moduleName, ''); //`${moduleName}.xml`;
25 const moduleExports = resolvedCodeModuleName ? global.loadModule(resolvedCodeModuleName, true) : null;
26 if (moduleExports && moduleExports.createPage) {
27 // Exports has a createPage() method
28 const view = moduleExports.createPage();
29 const resolvedCssModuleName = resolveModuleName(moduleName, 'css'); //entry.moduleName + ".css";
30 if (resolvedCssModuleName) {
31 view.addCssFile(resolvedCssModuleName);
32 }
33 return view;
34 }
35 else {
36 let componentView;
37 if (__UI_USE_XML_PARSER__) {
38 const componentModule = loadInternal(moduleName, moduleExports);
39 componentView = componentModule && componentModule.component;
40 }
41 else {
42 const resolvedXmlModuleName = resolveModuleName(moduleName, 'xml');
43 const componentModule = resolvedXmlModuleName ? global.loadModule(resolvedXmlModuleName, true) : null;
44 if (componentModule?.default) {
45 componentView = new componentModule.default();
46 }
47 else {
48 throw new Error('Failed to load component from module: ' + moduleName);
49 }
50 }
51 return componentView;
52 }
53 }
54 throw new Error('Failed to load page XML file for module: ' + entry.moduleName);
55 }
56 static parse(value, context) {
57 if (typeof value === 'function') {
58 return value();
59 }
60 else {
61 const exports = context ? getExports(context) : undefined;
62 const componentModule = parseInternal(value, exports);
63 return componentModule && componentModule.component;
64 }
65 }
66 static load(pathOrOptions, context) {
67 let componentModule;
68 if (typeof pathOrOptions === 'string') {
69 const moduleName = sanitizeModuleName(pathOrOptions);
70 componentModule = loadInternal(moduleName, context);
71 }
72 else {
73 componentModule = loadCustomComponent(pathOrOptions.path, pathOrOptions.name, pathOrOptions.attributes, pathOrOptions.exports, pathOrOptions.page, true);
74 }
75 return componentModule && componentModule.component;
76 }
77 static parseMultipleTemplates(value, context) {
78 const dummyComponent = `<ListView><ListView.itemTemplates>${value}</ListView.itemTemplates></ListView>`;
79 return parseInternal(dummyComponent, context).component['itemTemplates'];
80 }
81}
82// ui plugin developers can add to these to define their own custom types if needed
83Builder.knownTemplates = new Set(['itemTemplate']);
84Builder.knownMultiTemplates = new Set(['itemTemplates']);
85Builder.knownCollections = new Set(['items', 'spans', 'actionItems']);
86export function parse(value, context) {
87 console.log('parse() is deprecated. Use Builder.parse() instead.');
88 return Builder.parse(value, context);
89}
90export function parseMultipleTemplates(value, context) {
91 console.log('parseMultipleTemplates() is deprecated. Use Builder.parseMultipleTemplates() instead.');
92 return Builder.parseMultipleTemplates(value, context);
93}
94export function load(pathOrOptions, context) {
95 console.log('load() is deprecated. Use Builder.load() instead.');
96 return Builder.load(pathOrOptions, context);
97}
98export function createViewFromEntry(entry) {
99 console.log('createViewFromEntry() is deprecated. Use Builder.createViewFromEntry() instead.');
100 return Builder.createViewFromEntry(entry);
101}
102function loadInternal(moduleName, moduleExports) {
103 let componentModule;
104 const resolvedXmlModule = resolveModuleName(moduleName, 'xml');
105 if (resolvedXmlModule) {
106 const text = global.loadModule(resolvedXmlModule, true);
107 componentModule = parseInternal(text, moduleExports, resolvedXmlModule, moduleName);
108 }
109 const componentView = componentModule && componentModule.component;
110 if (componentView) {
111 // Save exports to root component (will be used for templates).
112 componentView.exports = moduleExports;
113 // Save _moduleName - used for livesync
114 componentView._moduleName = moduleName;
115 }
116 if (!componentModule) {
117 throw new Error('Failed to load component from module: ' + moduleName);
118 }
119 return componentModule;
120}
121export function loadCustomComponent(componentNamespace, componentName, attributes, context, parentPage, isRootComponent = true, moduleNamePath) {
122 if (!parentPage && context) {
123 // Read the parent page that was passed down below
124 // https://github.com/NativeScript/NativeScript/issues/1639
125 parentPage = context['_parentPage'];
126 delete context['_parentPage'];
127 }
128 let result;
129 componentNamespace = sanitizeModuleName(componentNamespace);
130 const moduleName = `${componentNamespace}/${componentName}`;
131 const resolvedCodeModuleName = resolveModuleName(moduleName, '');
132 const resolvedXmlModuleName = resolveModuleName(moduleName, 'xml');
133 let resolvedCssModuleName = resolveModuleName(moduleName, 'css');
134 if (resolvedXmlModuleName) {
135 // Custom components with XML
136 let subExports = context;
137 if (resolvedCodeModuleName) {
138 // Component has registered code module.
139 subExports = global.loadModule(resolvedCodeModuleName, true);
140 }
141 // Pass the parent page down the chain in case of custom components nested on many levels. Use the context for piggybacking.
142 // https://github.com/NativeScript/NativeScript/issues/1639
143 if (!subExports) {
144 subExports = {};
145 }
146 subExports['_parentPage'] = parentPage;
147 result = loadInternal(moduleName, subExports);
148 // Attributes will be transferred to the custom component
149 if (isDefined(result) && isDefined(result.component) && isDefined(attributes)) {
150 for (const attr in attributes) {
151 setPropertyValue(result.component, subExports, context, attr, attributes[attr]);
152 }
153 }
154 }
155 else {
156 // Custom components without XML
157 result = getComponentModule(componentName, componentNamespace, attributes, context, moduleNamePath, isRootComponent);
158 // The namespace is the JS module and the (componentName is the name of the class in the module)
159 // So if there is no componentNamespace/componentName.{qualifiers}.css we should also look for
160 // componentNamespace.{qualifiers}.css
161 if (!resolvedCssModuleName) {
162 resolvedCssModuleName = resolveModuleName(componentNamespace, 'css');
163 }
164 }
165 // Add CSS from webpack module if exists.
166 if (parentPage && resolvedCssModuleName) {
167 parentPage.addCssFile(resolvedCssModuleName);
168 }
169 return result;
170}
171export function getExports(instance) {
172 const isView = !!instance._domId;
173 if (!isView) {
174 return instance.exports || instance;
175 }
176 let exportObject = instance.exports;
177 let parent = instance.parent;
178 while (exportObject === undefined && parent) {
179 exportObject = parent.exports;
180 parent = parent.parent;
181 }
182 return exportObject;
183}
184function parseInternal(value, context, xmlModule, moduleName) {
185 if (__UI_USE_XML_PARSER__) {
186 let start;
187 let ui;
188 const errorFormat = debug && xmlModule ? xml2ui.SourceErrorFormat(xmlModule) : xml2ui.PositionErrorFormat;
189 const componentSourceTracker = debug && xmlModule
190 ? xml2ui.ComponentSourceTracker(xmlModule)
191 : () => {
192 // no-op
193 };
194 (start = new xml2ui.XmlStringParser(errorFormat)).pipe(new xml2ui.PlatformFilter()).pipe(new xml2ui.XmlStateParser((ui = new xml2ui.ComponentParser(context, errorFormat, componentSourceTracker, moduleName))));
195 start.parse(value);
196 return ui.rootComponentModule;
197 }
198 else {
199 return null;
200 }
201}
202//# sourceMappingURL=index.js.map
\No newline at end of file