You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
5.0 KiB
163 lines
5.0 KiB
""" |
|
Functionality for creating JS modules of various formats, including AMD and UMD. |
|
""" |
|
|
|
import re |
|
|
|
|
|
# Immediately Invoked Function Expression (IIFE) |
|
HIDDEN = """ |
|
(function () { |
|
|
|
"use strict"; |
|
|
|
{code} |
|
|
|
})(); |
|
""".lstrip() |
|
|
|
|
|
SIMPLE = """ |
|
(function (root, factory) { |
|
root.{save_name} = factory(); |
|
}(this, function () { |
|
|
|
"use strict"; |
|
|
|
{code} |
|
|
|
return {exports}; |
|
})); |
|
""".lstrip() |
|
|
|
|
|
AMD = """ |
|
define("{name}", [{dep_strings}], function ({dep_names}) { |
|
|
|
"use strict"; |
|
|
|
{code} |
|
|
|
return {exports}; |
|
}); |
|
""".lstrip() |
|
|
|
AMD_FLEXX = "flexx." + AMD |
|
|
|
|
|
# https://github.com/umdjs/umd/blob/master/returnExports.js |
|
UMD = """ |
|
(function (root, factory) { |
|
if (typeof define === 'function' && define.amd) { |
|
// AMD. Register as an anonymous module. |
|
define("{name}", [{dep_strings}], factory); |
|
} else if (typeof exports !== 'undefined') { |
|
// Node or CommonJS |
|
module.exports = factory({dep_requires}); |
|
if (typeof window === 'undefined') { |
|
root.{save_name} = module.exports; // also create global module in Node |
|
} |
|
} else { |
|
// Browser globals (root is window) |
|
root.{save_name} = factory({dep_fullnames}); |
|
} |
|
}(this, function ({dep_names}) { |
|
|
|
"use strict"; |
|
|
|
{code} |
|
|
|
return {exports}; |
|
})); |
|
""".lstrip() |
|
|
|
|
|
def isidentifier(s): |
|
# http://stackoverflow.com/questions/2544972/ |
|
if not isinstance(s, str): |
|
return False |
|
return re.match(r'^\w+$', s, re.UNICODE) and re.match(r'^[0-9]', s) is None |
|
|
|
|
|
def create_js_module(name, code, imports, exports, type='umd'): |
|
""" Wrap the given code in an AMD module. |
|
|
|
Note that "use strict" is added to the top of the module body. PScript |
|
does not deal with license strings; the caller should do that. |
|
|
|
Parameters: |
|
name (str): the name of the module. |
|
code (str): the JS code to wrap. |
|
imports (list): the imports for this module, as string names of the |
|
dependencies. Optionally, 'as' can be used to make a dependency |
|
available under a specific name (e.g. 'foo.js as foo'). |
|
exports (str, list): the result of this module (i.e. what other modules |
|
get when they import this module. Can be a JS expression or a list |
|
of names to export. |
|
type (str): the type of module to export, valid values are |
|
'hidden', 'simple' (save module on root), 'amd' , 'amd-flexx' and |
|
'umd' (case insensitive). Default 'umd'. |
|
""" |
|
|
|
# Check input args |
|
if not isinstance(name, str) or not name: |
|
raise ValueError('create_module() name arg must be a (nonempty) string.') |
|
if not isinstance(code, str): |
|
raise ValueError('create_module() code arg must be a string.') |
|
if not isinstance(imports, (tuple, list)): |
|
raise ValueError('create_module() imports arg must be a string.') |
|
if not isinstance(exports, (str, tuple, list)): |
|
raise ValueError('create_module() exports arg must be a string or list.') |
|
|
|
# Process imports |
|
deps, dep_names = [], [] |
|
for imp in imports: |
|
if not isinstance(imp, str): |
|
raise ValueError('Elements in create_module() imports must be str.') |
|
if ' as ' in imp: |
|
dep, dep_name = imp.split(' as ', 1) |
|
else: |
|
dep = dep_name = imp |
|
if '.' in dep_name: |
|
raise ValueError('Import %r has dots, have you used "as"?' % dep_name) |
|
deps.append(dep) |
|
dep_names.append(dep_name) |
|
|
|
# Process exports |
|
if isinstance(exports, str): |
|
return_val = exports |
|
else: # list |
|
for exp in exports: |
|
if not isinstance(exp, str): |
|
raise ValueError('Elements in create_module() exports must be str.') |
|
return_val = ', '.join(['%s: %s' % (exp, exp) for exp in exports]) |
|
return_val = '{' + return_val + '}' |
|
|
|
# Process type -> select template |
|
types = {'hidden': HIDDEN, 'simple': SIMPLE, |
|
'amd': AMD, 'umd': UMD, 'amd-flexx': AMD_FLEXX} |
|
if not isinstance(type, str): |
|
raise ValueError('create_js_module() type must be str.') |
|
if type.lower() not in types: |
|
raise ValueError('create_js_module() got invalid type %r' % type) |
|
template = types[type.lower()] |
|
|
|
# Derived information needed to populate the module templates |
|
save_name = lambda n: n.split('/')[-1].split('.')[0].replace('-', '_') |
|
dep_strings = ['"%s"' % dep for dep in deps] |
|
dep_fullnames = ['root.' + save_name(dep) for dep in deps] |
|
dep_requires = ['require("%s")' % dep for dep in deps] |
|
|
|
# Fill in the template |
|
for key, val in [('{name}', name), |
|
('{save_name}', save_name(name)), |
|
('{exports}', return_val), |
|
('{dep_names}', ', '.join(dep_names)), |
|
('{dep_strings}', ', '.join(dep_strings)), |
|
('{dep_fullnames}', ', '.join(dep_fullnames)), |
|
('{dep_requires}', ', '.join(dep_requires)), |
|
('{code}', code), # last! |
|
]: |
|
template = template.replace(key, val) |
|
|
|
return template
|
|
|