diff --git a/.husky/.gitignore b/.husky/.gitignore index c9cdc63b0..31354ec13 100644 --- a/.husky/.gitignore +++ b/.husky/.gitignore @@ -1 +1 @@ -_ \ No newline at end of file +_ diff --git a/docs/_config.yml b/docs/_config.yml index 2f7efbeab..fff4ab923 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1 +1 @@ -theme: jekyll-theme-minimal \ No newline at end of file +theme: jekyll-theme-minimal diff --git a/docs/jsdoc/templates/template/publish.js b/docs/jsdoc/templates/template/publish.js index 0c4276037..b340d6ed9 100644 --- a/docs/jsdoc/templates/template/publish.js +++ b/docs/jsdoc/templates/template/publish.js @@ -1,268 +1,271 @@ // changed from default template by MH on 1/7/2019, see "MH" below // changed from previous template by JC on 29/3/2020, see "JC" below -const doop = require('jsdoc/util/doop'); -const env = require('jsdoc/env'); -const fs = require('jsdoc/fs'); -const helper = require('jsdoc/util/templateHelper'); -const logger = require('jsdoc/util/logger'); -const path = require('jsdoc/path'); -const taffy = require('taffydb').taffy; -const template = require('jsdoc/template'); -const util = require('util'); - -const htmlsafe = helper.htmlsafe; -const linkto = helper.linkto; -const resolveAuthorLinks = helper.resolveAuthorLinks; -const hasOwnProp = Object.prototype.hasOwnProperty; - -let data; -let view; - -let outdir = path.normalize(env.opts.destination); +const doop = require('jsdoc/util/doop') +const env = require('jsdoc/env') +const fs = require('jsdoc/fs') +const helper = require('jsdoc/util/templateHelper') +const logger = require('jsdoc/util/logger') +const path = require('jsdoc/path') +const taffy = require('taffydb').taffy +const template = require('jsdoc/template') +const util = require('util') + +const htmlsafe = helper.htmlsafe +const linkto = helper.linkto +const resolveAuthorLinks = helper.resolveAuthorLinks +const hasOwnProp = Object.prototype.hasOwnProperty + +let data +let view + +let outdir = path.normalize(env.opts.destination) function find(spec) { - return helper.find(data, spec); + return helper.find(data, spec) } function tutoriallink(tutorial) { - return helper.toTutorial(tutorial, null, { - tag: 'em', - classname: 'disabled', - prefix: 'Tutorial: ' - }); + return helper.toTutorial(tutorial, null, { + tag: 'em', + classname: 'disabled', + prefix: 'Tutorial: ' + }) } function getAncestorLinks(doclet) { - return helper.getAncestorLinks(data, doclet); + return helper.getAncestorLinks(data, doclet) } function hashToLink(doclet, hash) { - let url; + let url - if ( !/^(#.+)/.test(hash) ) { - return hash; - } + if (!/^(#.+)/.test(hash)) { + return hash + } - url = helper.createLink(doclet); - url = url.replace(/(#.+|$)/, hash); + url = helper.createLink(doclet) + url = url.replace(/(#.+|$)/, hash) - return `${hash}`; + return `${hash}` } -function needsSignature({kind, type, meta}) { - let needsSig = false; - - // function and class definitions always get a signature - if (kind === 'function' || kind === 'class') { - needsSig = true; - } - // typedefs that contain functions get a signature, too - else if (kind === 'typedef' && type && type.names && - type.names.length) { - for (let i = 0, l = type.names.length; i < l; i++) { - if (type.names[i].toLowerCase() === 'function') { - needsSig = true; - break; - } - } - } - // and namespaces that are functions get a signature (but finding them is a - // bit messy) - else if (kind === 'namespace' && meta && meta.code && - meta.code.type && meta.code.type.match(/[Ff]unction/)) { - needsSig = true; +function needsSignature({ kind, type, meta }) { + let needsSig = false + + // function and class definitions always get a signature + if (kind === 'function' || kind === 'class') { + needsSig = true + } + // typedefs that contain functions get a signature, too + else if (kind === 'typedef' && type && type.names && type.names.length) { + for (let i = 0, l = type.names.length; i < l; i++) { + if (type.names[i].toLowerCase() === 'function') { + needsSig = true + break + } } - - return needsSig; + } + // and namespaces that are functions get a signature (but finding them is a + // bit messy) + else if ( + kind === 'namespace' && + meta && + meta.code && + meta.code.type && + meta.code.type.match(/[Ff]unction/) + ) { + needsSig = true + } + + return needsSig } -function getSignatureAttributes({optional, nullable}) { - const attributes = []; +function getSignatureAttributes({ optional, nullable }) { + const attributes = [] - if (optional) { - attributes.push('opt'); - } + if (optional) { + attributes.push('opt') + } - if (nullable === true) { - attributes.push('nullable'); - } - else if (nullable === false) { - attributes.push('non-null'); - } + if (nullable === true) { + attributes.push('nullable') + } else if (nullable === false) { + attributes.push('non-null') + } - return attributes; + return attributes } function updateItemName(item) { - const attributes = getSignatureAttributes(item); - let itemName = item.name || ''; - - if (item.variable) { - itemName = `…${itemName}`; - } - - if (attributes && attributes.length) { - itemName = util.format( '%s%s', itemName, - attributes.join(', ') ); - } - - return itemName; + const attributes = getSignatureAttributes(item) + let itemName = item.name || '' + + if (item.variable) { + itemName = `…${itemName}` + } + + if (attributes && attributes.length) { + itemName = util.format( + '%s%s', + itemName, + attributes.join(', ') + ) + } + + return itemName } function addParamAttributes(params) { - return params.filter(({name}) => name && !name.includes('.')).map(updateItemName); + return params.filter(({ name }) => name && !name.includes('.')).map(updateItemName) } function buildItemTypeStrings(item) { - const types = []; + const types = [] - if (item && item.type && item.type.names) { - item.type.names.forEach(name => { - types.push( linkto(name, htmlsafe(name)) ); - }); - } + if (item && item.type && item.type.names) { + item.type.names.forEach(name => { + types.push(linkto(name, htmlsafe(name))) + }) + } - return types; + return types } function buildAttribsString(attribs) { - let attribsString = ''; + let attribsString = '' - if (attribs && attribs.length) { - attribsString = htmlsafe( util.format('(%s) ', attribs.join(', ')) ); - } + if (attribs && attribs.length) { + attribsString = htmlsafe(util.format('(%s) ', attribs.join(', '))) + } - return attribsString; + return attribsString } function addNonParamAttributes(items) { - let types = []; + let types = [] - items.forEach(item => { - types = types.concat( buildItemTypeStrings(item) ); - }); + items.forEach(item => { + types = types.concat(buildItemTypeStrings(item)) + }) - return types; + return types } function addSignatureParams(f) { - const params = f.params ? addParamAttributes(f.params) : []; + const params = f.params ? addParamAttributes(f.params) : [] - f.signature = util.format( '%s(%s)', (f.signature || ''), params.join(', ') ); + f.signature = util.format('%s(%s)', f.signature || '', params.join(', ')) } function addSignatureReturns(f) { - const attribs = []; - let attribsString = ''; - let returnTypes = []; - let returnTypesString = ''; - const source = f.yields || f.returns; - - // jam all the return-type attributes into an array. this could create odd results (for example, - // if there are both nullable and non-nullable return types), but let's assume that most people - // who use multiple @return tags aren't using Closure Compiler type annotations, and vice-versa. - if (source) { - source.forEach(item => { - helper.getAttribs(item).forEach(attrib => { - if (!attribs.includes(attrib)) { - attribs.push(attrib); - } - }); - }); - - attribsString = buildAttribsString(attribs); - } + const attribs = [] + let attribsString = '' + let returnTypes = [] + let returnTypesString = '' + const source = f.yields || f.returns + + // jam all the return-type attributes into an array. this could create odd results (for example, + // if there are both nullable and non-nullable return types), but let's assume that most people + // who use multiple @return tags aren't using Closure Compiler type annotations, and vice-versa. + if (source) { + source.forEach(item => { + helper.getAttribs(item).forEach(attrib => { + if (!attribs.includes(attrib)) { + attribs.push(attrib) + } + }) + }) - if (source) { - returnTypes = addNonParamAttributes(source); - } - if (returnTypes.length) { - returnTypesString = util.format( ' → %s{%s}', attribsString, returnTypes.join('|') ); - } + attribsString = buildAttribsString(attribs) + } - f.signature = `${f.signature || ''}${returnTypesString}`; + if (source) { + returnTypes = addNonParamAttributes(source) + } + if (returnTypes.length) { + returnTypesString = util.format(' → %s{%s}', attribsString, returnTypes.join('|')) + } + + f.signature = `${f.signature || ''}${returnTypesString}` } function addSignatureTypes(f) { - const types = f.type ? buildItemTypeStrings(f) : []; + const types = f.type ? buildItemTypeStrings(f) : [] - f.signature = `${f.signature || ''}${types.length ? ` :${types.join('|')}` : ''}`; + f.signature = `${f.signature || ''}${types.length ? ` :${types.join('|')}` : ''}` } function addAttribs(f) { - const attribs = helper.getAttribs(f); - const attribsString = buildAttribsString(attribs); + const attribs = helper.getAttribs(f) + const attribsString = buildAttribsString(attribs) - f.attribs = util.format('%s', attribsString); + f.attribs = util.format('%s', attribsString) } function shortenPaths(files, commonPrefix) { - Object.keys(files).forEach(file => { - files[file].shortened = files[file].resolved.replace(commonPrefix, '') - // always use forward slashes - .replace(/\\/g, '/'); - }); - - return files; + Object.keys(files).forEach(file => { + files[file].shortened = files[file].resolved + .replace(commonPrefix, '') + // always use forward slashes + .replace(/\\/g, '/') + }) + + return files } -function getPathFromDoclet({meta}) { - if (!meta) { - return null; - } +function getPathFromDoclet({ meta }) { + if (!meta) { + return null + } - return meta.path && meta.path !== 'null' ? - path.join(meta.path, meta.filename) : - meta.filename; + return meta.path && meta.path !== 'null' ? path.join(meta.path, meta.filename) : meta.filename } function generate(title, docs, filename, resolveLinks) { - let docData; - let html; - let outpath; + let docData + let html + let outpath - resolveLinks = resolveLinks !== false; + resolveLinks = resolveLinks !== false - docData = { - env: env, - title: title, - // remove tags from header, also see layout.tmpl - header: title.replace(/]*>/,"").replace(/<\/a>/,""), - docs: docs - }; + docData = { + env: env, + title: title, + // remove tags from header, also see layout.tmpl + header: title.replace(/]*>/, '').replace(/<\/a>/, ''), + docs: docs + } - outpath = path.join(outdir, filename); - html = view.render('container.tmpl', docData); + outpath = path.join(outdir, filename) + html = view.render('container.tmpl', docData) - if (resolveLinks) { - html = helper.resolveLinks(html); // turn {@link foo} into foo - } + if (resolveLinks) { + html = helper.resolveLinks(html) // turn {@link foo} into foo + } - fs.writeFileSync(outpath, html, 'utf8'); + fs.writeFileSync(outpath, html, 'utf8') } function generateSourceFiles(sourceFiles, encoding = 'utf8') { - Object.keys(sourceFiles).forEach(file => { - let source; - // links are keyed to the shortened path in each doclet's `meta.shortpath` property - const sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened); - - helper.registerLink(sourceFiles[file].shortened, sourceOutfile); - - try { - source = { - kind: 'source', - code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, encoding) ) - }; - } - catch (e) { - logger.error('Error while generating source file %s: %s', file, e.message); - } + Object.keys(sourceFiles).forEach(file => { + let source + // links are keyed to the shortened path in each doclet's `meta.shortpath` property + const sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened) + + helper.registerLink(sourceFiles[file].shortened, sourceOutfile) + + try { + source = { + kind: 'source', + code: helper.htmlsafe(fs.readFileSync(sourceFiles[file].resolved, encoding)) + } + } catch (e) { + logger.error('Error while generating source file %s: %s', file, e.message) + } - generate(`Source: ${sourceFiles[file].shortened}`, [source], sourceOutfile, - false); - }); + generate(`Source: ${sourceFiles[file].shortened}`, [source], sourceOutfile, false) + }) } /** @@ -277,71 +280,70 @@ function generateSourceFiles(sourceFiles, encoding = 'utf8') { * @param {Array.} modules - The array of module doclets to search. */ function attachModuleSymbols(doclets, modules) { - const symbols = {}; - - // build a lookup table - doclets.forEach(symbol => { - symbols[symbol.longname] = symbols[symbol.longname] || []; - symbols[symbol.longname].push(symbol); - }); - - modules.forEach(module => { - if (symbols[module.longname]) { - module.modules = symbols[module.longname] - // Only show symbols that have a description. Make an exception for classes, because - // we want to show the constructor-signature heading no matter what. - .filter(({description, kind}) => description || kind === 'class') - .map(symbol => { - symbol = doop(symbol); - - if (symbol.kind === 'class' || symbol.kind === 'function') { - symbol.name = `${symbol.name.replace('module:', '(require("')}"))`; - } - - return symbol; - }); - } - }); + const symbols = {} + + // build a lookup table + doclets.forEach(symbol => { + symbols[symbol.longname] = symbols[symbol.longname] || [] + symbols[symbol.longname].push(symbol) + }) + + modules.forEach(module => { + if (symbols[module.longname]) { + module.modules = symbols[module.longname] + // Only show symbols that have a description. Make an exception for classes, because + // we want to show the constructor-signature heading no matter what. + .filter(({ description, kind }) => description || kind === 'class') + .map(symbol => { + symbol = doop(symbol) + + if (symbol.kind === 'class' || symbol.kind === 'function') { + symbol.name = `${symbol.name.replace('module:', '(require("')}"))` + } + + return symbol + }) + } + }) } function buildMemberNav(items, itemHeading, itemsSeen, linktoFn) { - let nav = ''; - - if (items.length) { - let itemsNav = ''; - - items.forEach(item => { - let displayName; - - if ( !hasOwnProp.call(item, 'longname') ) { - itemsNav += `
  • ${linktoFn('', item.name)}
  • `; - } - else if ( !hasOwnProp.call(itemsSeen, item.longname) ) { - if (env.conf.templates.default.useLongnameInNav) { - displayName = item.longname; - } else { - displayName = item.name; - } - itemsNav += `
  • ${linktoFn(item.longname, displayName.replace(/\b(module|event):/g, ''))}
  • `; - - itemsSeen[item.longname] = true; - } - }); - - if (itemsNav !== '') { - nav += `

    ${itemHeading}

      ${itemsNav}
    `; + let nav = '' + + if (items.length) { + let itemsNav = '' + + items.forEach(item => { + let displayName + + if (!hasOwnProp.call(item, 'longname')) { + itemsNav += `
  • ${linktoFn('', item.name)}
  • ` + } else if (!hasOwnProp.call(itemsSeen, item.longname)) { + if (env.conf.templates.default.useLongnameInNav) { + displayName = item.longname + } else { + displayName = item.name } + itemsNav += `
  • ${linktoFn(item.longname, displayName.replace(/\b(module|event):/g, ''))}
  • ` + + itemsSeen[item.longname] = true + } + }) + + if (itemsNav !== '') { + nav += `

    ${itemHeading}

      ${itemsNav}
    ` } + } - return nav; + return nav } function linktoTutorial(longName, name) { - return tutoriallink(name); + return tutoriallink(name) } function linktoExternal(longName, name) { - return linkto(longName, name.replace(/(^"|"$)/g, '')); + return linkto(longName, name.replace(/(^"|"$)/g, '')) } /** @@ -359,47 +361,46 @@ function linktoExternal(longName, name) { * @return {string} The HTML for the navigation sidebar. */ function buildNav(members) { - let globalNav; - let nav = ''; // '

    Home

    '; - const seen = {}; - const seenTutorials = {}; - - nav += buildMemberNav(members.modules, 'Modules', {}, linkto); - nav += buildMemberNav(members.externals, 'Externals', seen, linktoExternal); - nav += buildMemberNav(members.namespaces, 'Namespaces', seen, linkto); -// nav += buildMemberNav(members.classes, 'Classes', seen, linkto); - nav += buildMemberNav(members.interfaces, 'Interfaces', seen, linkto); - nav += buildMemberNav(members.events, 'Events', seen, linkto); - nav += buildMemberNav(members.mixins, 'Mixins', seen, linkto); - nav += buildMemberNav(members.tutorials, 'Tutorials', seenTutorials, linktoTutorial); - - if (members.globals.length) { - globalNav = ''; - - members.globals.forEach(({kind, longname, name}) => { - if ( kind !== 'typedef' && !hasOwnProp.call(seen, longname) ) { - globalNav += `
  • ${linkto(longname, name)}
  • `; - } - seen[longname] = true; - }); - - if (!globalNav) { - // turn the heading into a link so you can actually get to the global page - // MH: 9/7/19: use the basename of the folder as heading - // MH: 13/7/19: we turn "_" into " §", in order to have nice headings - // JC: 29/3/20: restrict above transformation to first "_" - const symbolReplacedName = path.basename(outdir).replace(/_/, " §"); - // JC: 29/3/20: change all remaining "_" to " " - const displayName = symbolReplacedName.replace(/_/g, " "); - const link = `${displayName}`; - nav += `

    ${linkto('global', 'Predeclared in '+ link)}

    `; - } - else { - nav += `

    Predeclared names

      ${globalNav}
    `; - } + let globalNav + let nav = '' // '

    Home

    '; + const seen = {} + const seenTutorials = {} + + nav += buildMemberNav(members.modules, 'Modules', {}, linkto) + nav += buildMemberNav(members.externals, 'Externals', seen, linktoExternal) + nav += buildMemberNav(members.namespaces, 'Namespaces', seen, linkto) + // nav += buildMemberNav(members.classes, 'Classes', seen, linkto); + nav += buildMemberNav(members.interfaces, 'Interfaces', seen, linkto) + nav += buildMemberNav(members.events, 'Events', seen, linkto) + nav += buildMemberNav(members.mixins, 'Mixins', seen, linkto) + nav += buildMemberNav(members.tutorials, 'Tutorials', seenTutorials, linktoTutorial) + + if (members.globals.length) { + globalNav = '' + + members.globals.forEach(({ kind, longname, name }) => { + if (kind !== 'typedef' && !hasOwnProp.call(seen, longname)) { + globalNav += `
  • ${linkto(longname, name)}
  • ` + } + seen[longname] = true + }) + + if (!globalNav) { + // turn the heading into a link so you can actually get to the global page + // MH: 9/7/19: use the basename of the folder as heading + // MH: 13/7/19: we turn "_" into " §", in order to have nice headings + // JC: 29/3/20: restrict above transformation to first "_" + const symbolReplacedName = path.basename(outdir).replace(/_/, ' §') + // JC: 29/3/20: change all remaining "_" to " " + const displayName = symbolReplacedName.replace(/_/g, ' ') + const link = `${displayName}` + nav += `

    ${linkto('global', 'Predeclared in ' + link)}

    ` + } else { + nav += `

    Predeclared names

      ${globalNav}
    ` } + } - return nav; + return nav } /** @@ -408,315 +409,319 @@ function buildNav(members) { @param {Tutorial} tutorials */ exports.publish = (taffyData, opts, tutorials) => { - let classes; - let conf; - let externals; - let files; - let fromDir; - let globalUrl; - let indexUrl; - let interfaces; - let members; - let mixins; - let modules; - let namespaces; - let outputSourceFiles; - let packageInfo; - let packages; - const sourceFilePaths = []; - let sourceFiles = {}; - let staticFileFilter; - let staticFilePaths; - let staticFiles; - let staticFileScanner; - let templatePath; - - data = taffyData; - - conf = env.conf.templates || {}; - conf.default = conf.default || {}; - - templatePath = path.normalize(opts.template); - view = new template.Template( path.join(templatePath, 'tmpl') ); - - // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness - // doesn't try to hand them out later - indexUrl = helper.getUniqueFilename('index'); - // don't call registerLink() on this one! 'index' is also a valid longname - - globalUrl = helper.getUniqueFilename('global'); - helper.registerLink('global', globalUrl); - - // set up templating - view.layout = conf.default.layoutFile ? - path.getResourcePath(path.dirname(conf.default.layoutFile), - path.basename(conf.default.layoutFile) ) : - 'layout.tmpl'; - - // set up tutorials for helper - helper.setTutorials(tutorials); - - data = helper.prune(data); - data.sort('longname, version, since'); - helper.addEventListeners(data); - - data().each(doclet => { - let sourcePath; - - doclet.attribs = ''; - - if (doclet.examples) { - doclet.examples = doclet.examples.map(example => { - let caption; - let code; - - if (example.match(/^\s*([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) { - caption = RegExp.$1; - code = RegExp.$3; - } - - return { - caption: caption || '', - code: code || example - }; - }); - } - if (doclet.see) { - doclet.see.forEach((seeItem, i) => { - doclet.see[i] = hashToLink(doclet, seeItem); - }); + let classes + let conf + let externals + let files + let fromDir + let globalUrl + let indexUrl + let interfaces + let members + let mixins + let modules + let namespaces + let outputSourceFiles + let packageInfo + let packages + const sourceFilePaths = [] + let sourceFiles = {} + let staticFileFilter + let staticFilePaths + let staticFiles + let staticFileScanner + let templatePath + + data = taffyData + + conf = env.conf.templates || {} + conf.default = conf.default || {} + + templatePath = path.normalize(opts.template) + view = new template.Template(path.join(templatePath, 'tmpl')) + + // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness + // doesn't try to hand them out later + indexUrl = helper.getUniqueFilename('index') + // don't call registerLink() on this one! 'index' is also a valid longname + + globalUrl = helper.getUniqueFilename('global') + helper.registerLink('global', globalUrl) + + // set up templating + view.layout = conf.default.layoutFile + ? path.getResourcePath( + path.dirname(conf.default.layoutFile), + path.basename(conf.default.layoutFile) + ) + : 'layout.tmpl' + + // set up tutorials for helper + helper.setTutorials(tutorials) + + data = helper.prune(data) + data.sort('longname, version, since') + helper.addEventListeners(data) + + data().each(doclet => { + let sourcePath + + doclet.attribs = '' + + if (doclet.examples) { + doclet.examples = doclet.examples.map(example => { + let caption + let code + + if (example.match(/^\s*([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) { + caption = RegExp.$1 + code = RegExp.$3 } - // build a list of source files - if (doclet.meta) { - sourcePath = getPathFromDoclet(doclet); - sourceFiles[sourcePath] = { - resolved: sourcePath, - shortened: null - }; - if (!sourceFilePaths.includes(sourcePath)) { - sourceFilePaths.push(sourcePath); - } + return { + caption: caption || '', + code: code || example } - }); - - // update outdir if necessary, then create outdir - packageInfo = ( find({kind: 'package'}) || [] )[0]; - if (packageInfo && packageInfo.name) { - outdir = path.join( outdir, packageInfo.name, (packageInfo.version || '') ); + }) } - fs.mkPath(outdir); - - // copy the template's static files to outdir - fromDir = path.join(templatePath, 'static'); - staticFiles = fs.ls(fromDir, 3); - - staticFiles.forEach(fileName => { - const toDir = fs.toDir( fileName.replace(fromDir, outdir) ); - - fs.mkPath(toDir); - fs.copyFileSync(fileName, toDir); - }); - - // copy user-specified static files to outdir - if (conf.default.staticFiles) { - // The canonical property name is `include`. We accept `paths` for backwards compatibility - // with a bug in JSDoc 3.2.x. - staticFilePaths = conf.default.staticFiles.include || - conf.default.staticFiles.paths || - []; - staticFileFilter = new (require('jsdoc/src/filter').Filter)(conf.default.staticFiles); - staticFileScanner = new (require('jsdoc/src/scanner').Scanner)(); - - staticFilePaths.forEach(filePath => { - let extraStaticFiles; - - filePath = path.resolve(env.pwd, filePath); - extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter); - - extraStaticFiles.forEach(fileName => { - const sourcePath = fs.toDir(filePath); - const toDir = fs.toDir( fileName.replace(sourcePath, outdir) ); - - fs.mkPath(toDir); - fs.copyFileSync(fileName, toDir); - }); - }); + if (doclet.see) { + doclet.see.forEach((seeItem, i) => { + doclet.see[i] = hashToLink(doclet, seeItem) + }) } - if (sourceFilePaths.length) { - sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) ); + // build a list of source files + if (doclet.meta) { + sourcePath = getPathFromDoclet(doclet) + sourceFiles[sourcePath] = { + resolved: sourcePath, + shortened: null + } + if (!sourceFilePaths.includes(sourcePath)) { + sourceFilePaths.push(sourcePath) + } } - data().each(doclet => { - let docletPath; - const url = helper.createLink(doclet); - - helper.registerLink(doclet.longname, url); - - // add a shortened version of the full path - if (doclet.meta) { - docletPath = getPathFromDoclet(doclet); - docletPath = sourceFiles[docletPath].shortened; - if (docletPath) { - doclet.meta.shortpath = docletPath; - } - } - }); + }) + + // update outdir if necessary, then create outdir + packageInfo = (find({ kind: 'package' }) || [])[0] + if (packageInfo && packageInfo.name) { + outdir = path.join(outdir, packageInfo.name, packageInfo.version || '') + } + fs.mkPath(outdir) + + // copy the template's static files to outdir + fromDir = path.join(templatePath, 'static') + staticFiles = fs.ls(fromDir, 3) + + staticFiles.forEach(fileName => { + const toDir = fs.toDir(fileName.replace(fromDir, outdir)) + + fs.mkPath(toDir) + fs.copyFileSync(fileName, toDir) + }) + + // copy user-specified static files to outdir + if (conf.default.staticFiles) { + // The canonical property name is `include`. We accept `paths` for backwards compatibility + // with a bug in JSDoc 3.2.x. + staticFilePaths = conf.default.staticFiles.include || conf.default.staticFiles.paths || [] + staticFileFilter = new (require('jsdoc/src/filter').Filter)(conf.default.staticFiles) + staticFileScanner = new (require('jsdoc/src/scanner').Scanner)() + + staticFilePaths.forEach(filePath => { + let extraStaticFiles + + filePath = path.resolve(env.pwd, filePath) + extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter) + + extraStaticFiles.forEach(fileName => { + const sourcePath = fs.toDir(filePath) + const toDir = fs.toDir(fileName.replace(sourcePath, outdir)) + + fs.mkPath(toDir) + fs.copyFileSync(fileName, toDir) + }) + }) + } + + if (sourceFilePaths.length) { + sourceFiles = shortenPaths(sourceFiles, path.commonPrefix(sourceFilePaths)) + } + data().each(doclet => { + let docletPath + const url = helper.createLink(doclet) + + helper.registerLink(doclet.longname, url) + + // add a shortened version of the full path + if (doclet.meta) { + docletPath = getPathFromDoclet(doclet) + docletPath = sourceFiles[docletPath].shortened + if (docletPath) { + doclet.meta.shortpath = docletPath + } + } + }) - data().each(doclet => { - const url = helper.longnameToUrl[doclet.longname]; + data().each(doclet => { + const url = helper.longnameToUrl[doclet.longname] - if (url.includes('#')) { - doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); - } - else { - doclet.id = doclet.name; - } + if (url.includes('#')) { + doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop() + } else { + doclet.id = doclet.name + } - if ( needsSignature(doclet) ) { - addSignatureParams(doclet); - addSignatureReturns(doclet); - addAttribs(doclet); - } - }); + if (needsSignature(doclet)) { + addSignatureParams(doclet) + addSignatureReturns(doclet) + addAttribs(doclet) + } + }) - // do this after the urls have all been generated - data().each(doclet => { - doclet.ancestors = getAncestorLinks(doclet); + // do this after the urls have all been generated + data().each(doclet => { + doclet.ancestors = getAncestorLinks(doclet) - if (doclet.kind === 'member') { - addSignatureTypes(doclet); - addAttribs(doclet); - } + if (doclet.kind === 'member') { + addSignatureTypes(doclet) + addAttribs(doclet) + } - if (doclet.kind === 'constant') { - addSignatureTypes(doclet); - addAttribs(doclet); - doclet.kind = 'member'; + if (doclet.kind === 'constant') { + addSignatureTypes(doclet) + addAttribs(doclet) + doclet.kind = 'member' + } + }) + + members = helper.getMembers(data) + members.tutorials = tutorials.children + + // output pretty-printed source files by default + outputSourceFiles = conf.default && conf.default.outputSourceFiles !== false + + // add template helpers + view.find = find + view.linkto = linkto + view.resolveAuthorLinks = resolveAuthorLinks + view.tutoriallink = tutoriallink + view.htmlsafe = htmlsafe + view.outputSourceFiles = outputSourceFiles + + // once for all + view.nav = buildNav(members) + attachModuleSymbols(find({ longname: { left: 'module:' } }), members.modules) + + // generate the pretty-printed source files first so other pages can link to them + if (outputSourceFiles) { + generateSourceFiles(sourceFiles, opts.encoding) + } + + // MH: 9/7/19: use the basename of the folder as heading + let baseName = path.basename(outdir) + // MH: 13/7/19: turn "_" into " §", in order to have nice headings + // JC: 29/3/20: restrict above transformation to first "_" + const symbolReplacedName = baseName.replace(/_/, ' §') + // JC: 29/3/20: change all remaining "_" to " ", then capitalize each word + const spacedName = symbolReplacedName.replace(/_/g, ' ') + // Arsalan: 21/4/20: capitalize the first letter of each word, including those separated by a hyphen + const displayName = spacedName.replace(/(^|[\s-])\S/g, firstLetter => firstLetter.toUpperCase()) + + const link = `${displayName}` + + // MH: 23/4/2020: added else to conditional to allow for empty libs + if (members.globals.length) { + generate('Predeclared in ' + link, [{ kind: 'globalobj' }], globalUrl) + } else { + generate('No names predeclared in ' + link, [{ kind: 'globalobj' }], globalUrl) + } + + // index page displays information from package.json and lists files + files = find({ kind: 'file' }) + packages = find({ kind: 'package' }) + + generate( + displayName, // MH: 1/7/2019: This was: + // generate('Home', + packages + .concat([ + { + kind: 'mainpage', + readme: opts.readme, + longname: opts.mainpagetitle ? opts.mainpagetitle : 'Main Page' } - }); - - members = helper.getMembers(data); - members.tutorials = tutorials.children; - - // output pretty-printed source files by default - outputSourceFiles = conf.default && conf.default.outputSourceFiles !== false; - - // add template helpers - view.find = find; - view.linkto = linkto; - view.resolveAuthorLinks = resolveAuthorLinks; - view.tutoriallink = tutoriallink; - view.htmlsafe = htmlsafe; - view.outputSourceFiles = outputSourceFiles; - - // once for all - view.nav = buildNav(members); - attachModuleSymbols( find({ longname: {left: 'module:'} }), members.modules ); - - // generate the pretty-printed source files first so other pages can link to them - if (outputSourceFiles) { - generateSourceFiles(sourceFiles, opts.encoding); + ]) + .concat(files), + indexUrl + ) + + // set up the lists that we'll use to generate pages + classes = taffy(members.classes) + modules = taffy(members.modules) + namespaces = taffy(members.namespaces) + mixins = taffy(members.mixins) + externals = taffy(members.externals) + interfaces = taffy(members.interfaces) + + Object.keys(helper.longnameToUrl).forEach(longname => { + const myClasses = helper.find(classes, { longname: longname }) + const myExternals = helper.find(externals, { longname: longname }) + const myInterfaces = helper.find(interfaces, { longname: longname }) + const myMixins = helper.find(mixins, { longname: longname }) + const myModules = helper.find(modules, { longname: longname }) + const myNamespaces = helper.find(namespaces, { longname: longname }) + + if (myModules.length) { + generate(`Module: ${myModules[0].name}`, myModules, helper.longnameToUrl[longname]) } - // MH: 9/7/19: use the basename of the folder as heading - let baseName = path.basename(outdir); - // MH: 13/7/19: turn "_" into " §", in order to have nice headings - // JC: 29/3/20: restrict above transformation to first "_" - const symbolReplacedName = baseName.replace(/_/, " §"); - // JC: 29/3/20: change all remaining "_" to " ", then capitalize each word - const spacedName = symbolReplacedName.replace(/_/g, " "); - // Arsalan: 21/4/20: capitalize the first letter of each word, including those separated by a hyphen - const displayName = spacedName.replace(/(^|[\s-])\S/g, firstLetter => firstLetter.toUpperCase()); - - const link = `${displayName}`; - - // MH: 23/4/2020: added else to conditional to allow for empty libs - if (members.globals.length) { - generate('Predeclared in '+ link, [{kind: 'globalobj'}], globalUrl); - } else { - generate('No names predeclared in ' + link, [{kind: 'globalobj'}], globalUrl); + if (myClasses.length) { + generate(`Class: ${myClasses[0].name}`, myClasses, helper.longnameToUrl[longname]) } - // index page displays information from package.json and lists files - files = find({kind: 'file'}); - packages = find({kind: 'package'}); - - generate(displayName, // MH: 1/7/2019: This was: - // generate('Home', - packages.concat( - [{ - kind: 'mainpage', - readme: opts.readme, - longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page' - }] - ).concat(files), indexUrl); - - // set up the lists that we'll use to generate pages - classes = taffy(members.classes); - modules = taffy(members.modules); - namespaces = taffy(members.namespaces); - mixins = taffy(members.mixins); - externals = taffy(members.externals); - interfaces = taffy(members.interfaces); - - Object.keys(helper.longnameToUrl).forEach(longname => { - const myClasses = helper.find(classes, {longname: longname}); - const myExternals = helper.find(externals, {longname: longname}); - const myInterfaces = helper.find(interfaces, {longname: longname}); - const myMixins = helper.find(mixins, {longname: longname}); - const myModules = helper.find(modules, {longname: longname}); - const myNamespaces = helper.find(namespaces, {longname: longname}); - - if (myModules.length) { - generate(`Module: ${myModules[0].name}`, myModules, helper.longnameToUrl[longname]); - } + if (myNamespaces.length) { + generate(`Namespace: ${myNamespaces[0].name}`, myNamespaces, helper.longnameToUrl[longname]) + } - if (myClasses.length) { - generate(`Class: ${myClasses[0].name}`, myClasses, helper.longnameToUrl[longname]); - } + if (myMixins.length) { + generate(`Mixin: ${myMixins[0].name}`, myMixins, helper.longnameToUrl[longname]) + } - if (myNamespaces.length) { - generate(`Namespace: ${myNamespaces[0].name}`, myNamespaces, helper.longnameToUrl[longname]); - } + if (myExternals.length) { + generate(`External: ${myExternals[0].name}`, myExternals, helper.longnameToUrl[longname]) + } - if (myMixins.length) { - generate(`Mixin: ${myMixins[0].name}`, myMixins, helper.longnameToUrl[longname]); - } + if (myInterfaces.length) { + generate(`Interface: ${myInterfaces[0].name}`, myInterfaces, helper.longnameToUrl[longname]) + } + }) + + // TODO: move the tutorial functions to templateHelper.js + function generateTutorial(title, tutorial, filename) { + const tutorialData = { + title: title, + header: tutorial.title, + content: tutorial.parse(), + children: tutorial.children + } + const tutorialPath = path.join(outdir, filename) + let html = view.render('tutorial.tmpl', tutorialData) - if (myExternals.length) { - generate(`External: ${myExternals[0].name}`, myExternals, helper.longnameToUrl[longname]); - } + // yes, you can use {@link} in tutorials too! + html = helper.resolveLinks(html) // turn {@link foo} into foo - if (myInterfaces.length) { - generate(`Interface: ${myInterfaces[0].name}`, myInterfaces, helper.longnameToUrl[longname]); - } - }); - - // TODO: move the tutorial functions to templateHelper.js - function generateTutorial(title, tutorial, filename) { - const tutorialData = { - title: title, - header: tutorial.title, - content: tutorial.parse(), - children: tutorial.children - }; - const tutorialPath = path.join(outdir, filename); - let html = view.render('tutorial.tmpl', tutorialData); - - // yes, you can use {@link} in tutorials too! - html = helper.resolveLinks(html); // turn {@link foo} into foo - - fs.writeFileSync(tutorialPath, html, 'utf8'); - } + fs.writeFileSync(tutorialPath, html, 'utf8') + } - // tutorials can have only one parent so there is no risk for loops - function saveChildren({children}) { - children.forEach(child => { - generateTutorial(`Tutorial: ${child.title}`, child, helper.tutorialToUrl(child.name)); - saveChildren(child); - }); - } + // tutorials can have only one parent so there is no risk for loops + function saveChildren({ children }) { + children.forEach(child => { + generateTutorial(`Tutorial: ${child.title}`, child, helper.tutorialToUrl(child.name)) + saveChildren(child) + }) + } - saveChildren(tutorials); -}; + saveChildren(tutorials) +} diff --git a/docs/lib/array.js b/docs/lib/array.js index c9cd723a3..3c0920cfd 100644 --- a/docs/lib/array.js +++ b/docs/lib/array.js @@ -1,7 +1,7 @@ /** * **primitive**; returns * the current length of array x, which is 1 plus the - * highest index that has been used so far in an array assignment on + * highest index that has been used so far in an array assignment on * x. Here literal array expressions are counted too: The * array [10, 20, 30] has a length of 3. * Time: Θ(1), space: Θ(1) @@ -11,11 +11,10 @@ function array_length(x) {} /** - * **primitive**; returns true if x + * **primitive**; returns true if x * is an array, and false if it is not. * Time: Θ(1), space: Θ(1) * @param {value} x - given value * @returns {boolean} whether x is an array */ function is_array(x) {} - diff --git a/docs/lib/concurrency.js b/docs/lib/concurrency.js index 75fa7c269..46c057a5b 100644 --- a/docs/lib/concurrency.js +++ b/docs/lib/concurrency.js @@ -1,6 +1,6 @@ /** * Setup multiple threads for concurrent execution. For each - * function f_i, + * function f_i, * setup a thread t_i that executes the body of * f_i. Any parameters of f_i refer * to undefined during execution. diff --git a/docs/lib/continuation.js b/docs/lib/continuation.js index e357eea1d..39c794fcd 100755 --- a/docs/lib/continuation.js +++ b/docs/lib/continuation.js @@ -1,8 +1,7 @@ /** * Generate a continuation cont, - * and call f(cont). + * and call f(cont). * @param {function} f - A function of the form (cont) => ... * @returns the return value of f if cont is not consumed */ function call_cc(f) {} - diff --git a/docs/lib/empty.js b/docs/lib/empty.js index 2e3c9c1b0..1c2d1be97 100755 --- a/docs/lib/empty.js +++ b/docs/lib/empty.js @@ -1,4 +1,3 @@ /** * there are no predeclared names here */ - diff --git a/docs/lib/ev3.js b/docs/lib/ev3.js index 5d632ee36..81dbd77c7 100644 --- a/docs/lib/ev3.js +++ b/docs/lib/ev3.js @@ -5,8 +5,7 @@ * @returns {boolean} true if the peripheral is connected, false otherwise * @alias ev3_connected */ -var connected = function(obj) { -}; +var connected = function (obj) {} /** * Gets the motor connected to port A. @@ -14,8 +13,7 @@ var connected = function(obj) { * @returns {peripheral} The motor connected to port A * @alias ev3_motorA */ -var motorA = function() { -}; +var motorA = function () {} /** * Gets the motor connected to port B. @@ -23,8 +21,7 @@ var motorA = function() { * @returns {peripheral} The motor connected to port B * @alias ev3_motorB */ -var motorB = function() { -}; +var motorB = function () {} /** * Gets the motor connected to port C. @@ -32,8 +29,7 @@ var motorB = function() { * @returns {peripheral} The motor connected to port C * @alias ev3_motorC */ -var motorC = function() { -}; +var motorC = function () {} /** * Gets the motor connected to port D. @@ -41,9 +37,7 @@ var motorC = function() { * @returns {peripheral} The motor connected to port D * @alias ev3_motorD */ -var motorD = function() { -}; - +var motorD = function () {} /** * Causes the motor to rotate for a specified duration at the specified speed. @@ -55,8 +49,7 @@ var motorD = function() { * @param {number} speed - The speed to run at, in tacho counts per second * @alias ev3_runForTime */ -var runForTime = function(motor, time, speed) { -}; +var runForTime = function (motor, time, speed) {} /** * Causes the motor to rotate to the given absolute position (as reported by @@ -69,8 +62,7 @@ var runForTime = function(motor, time, speed) { * @param {number} speed - The speed to run at, in tacho counts per second * @alias ev3_runToAbsolutePosition */ -var runToAbsolutePosition = function(motor, position, speed) { -}; +var runToAbsolutePosition = function (motor, position, speed) {} /** * Causes the motor to rotate until the position reaches {@link ev3_motorGetPosition}() @@ -83,8 +75,7 @@ var runToAbsolutePosition = function(motor, position, speed) { * @param {number} speed - The speed to run at, in tacho counts per second * @alias ev3_runToRelativePosition */ -var runToRelativePosition = function(motor, position, speed) { -}; +var runToRelativePosition = function (motor, position, speed) {} /** * Gets the motor's current position, in pulses of the rotary encoder. @@ -93,8 +84,7 @@ var runToRelativePosition = function(motor, position, speed) { * @returns {number} The current position. * @alias ev3_motorGetPosition */ -var motorGetPosition = function(motor) { -} +var motorGetPosition = function (motor) {} /** * Gets the motor's current speed, in tacho counts per second. @@ -103,8 +93,7 @@ var motorGetPosition = function(motor) { * @returns {number} The current speed. * @alias ev3_motorGetSpeed */ -var motorGetSpeed = function(motor) { -} +var motorGetSpeed = function (motor) {} /** * Sets the speed the motor will run at the next time {@link ev3_motorStart} @@ -114,8 +103,7 @@ var motorGetSpeed = function(motor) { * @param {number} speed - The speed to run at, in tacho counts per second * @alias ev3_motorSetSpeed */ -var motorSetSpeed = function(motor, speed) { -} +var motorSetSpeed = function (motor, speed) {} /** * Causes the motor to start with the previously set speed and stop action @@ -124,8 +112,7 @@ var motorSetSpeed = function(motor, speed) { * @param {peripheral} motor - The motor * @alias ev3_motorStart */ -var motorStart = function(motor) { -}; +var motorStart = function (motor) {} /** * Causes the motor to stop using the previously set stop action. @@ -133,8 +120,7 @@ var motorStart = function(motor) { * @param {peripheral} motor - The motor * @alias ev3_motorStop */ -var motorStop = function(motor) { -}; +var motorStop = function (motor) {} /** * Sets the stop action of the motor. @@ -149,8 +135,7 @@ var motorStop = function(motor) { * @param {string} stopAction - The stop action to use. * @alias ev3_motorSetStopAction */ -var motorSetStopAction = function(motor, stopAction) { -} +var motorSetStopAction = function (motor, stopAction) {} /** * Gets the colour sensor connected any of ports 1, 2, 3 or 4. @@ -158,8 +143,7 @@ var motorSetStopAction = function(motor, stopAction) { * @returns {peripheral} The colour sensor. * @alias ev3_colorSensor */ -var colorSensor = function() { -}; +var colorSensor = function () {} /** * Gets the amount of red seen by the colour sensor. @@ -168,8 +152,7 @@ var colorSensor = function() { * @returns {number} The amount of red, in sensor-specific units. * @alias ev3_colorSensorRed */ -var colorSensorRed = function(colorSensor) { -} +var colorSensorRed = function (colorSensor) {} /** * Gets the amount of green seen by the colour sensor. @@ -178,8 +161,7 @@ var colorSensorRed = function(colorSensor) { * @returns {number} The amount of green, in sensor-specific units. * @alias ev3_colorSensorGreen */ -var colorSensorGreen = function(colorSensor) { -} +var colorSensorGreen = function (colorSensor) {} /** * Gets the amount of blue seen by the colour sensor. @@ -188,8 +170,7 @@ var colorSensorGreen = function(colorSensor) { * @returns {number} The amount of blue, in sensor-specific units. * @alias ev3_colorSensorBlue */ -var colorSensorBlue = function(colorSensor) { -} +var colorSensorBlue = function (colorSensor) {} /** * Gets the colour as seen by the colour sensor. @@ -208,8 +189,7 @@ var colorSensorBlue = function(colorSensor) { * @returns {number} A number representing the colour observed by the device. * @alias ev3_colorSensorGetColor */ -var colorSensorGetColor = function(colorSensor) { -} +var colorSensorGetColor = function (colorSensor) {} /** * Gets the reflected light intensity seen by the colour sensor. @@ -218,8 +198,7 @@ var colorSensorGetColor = function(colorSensor) { * @returns {number} The reflected light intensity, as a percentage from 0 to 100. * @alias ev3_reflectedLightIntensity */ -var reflectedLightIntensity = function(colorSensor) { -}; +var reflectedLightIntensity = function (colorSensor) {} /** * Gets the ambient light intensity seen by the colour sensor. @@ -228,8 +207,7 @@ var reflectedLightIntensity = function(colorSensor) { * @returns {number} The ambient light intensity, as a percentage from 0 to 100. * @alias ev3_ambientLightIntensity */ -var ambientLightIntensity = function(colorSensor) { -}; +var ambientLightIntensity = function (colorSensor) {} /** * Gets the touch sensor connected to port 1. @@ -237,8 +215,7 @@ var ambientLightIntensity = function(colorSensor) { * @returns {peripheral} The touch sensor. * @alias ev3_touchSensor1 */ -var touchSensor1 = function() { -}; +var touchSensor1 = function () {} /** * Gets the touch sensor connected to port 2. @@ -246,8 +223,7 @@ var touchSensor1 = function() { * @returns {peripheral} The touch sensor. * @alias ev3_touchSensor2 */ -var touchSensor2 = function() { -}; +var touchSensor2 = function () {} /** * Gets the touch sensor connected to port 3. @@ -255,8 +231,7 @@ var touchSensor2 = function() { * @returns {peripheral} The touch sensor. * @alias ev3_touchSensor3 */ -var touchSensor3 = function() { -}; +var touchSensor3 = function () {} /** * Gets the touch sensor connected to port 4. @@ -264,8 +239,7 @@ var touchSensor3 = function() { * @returns {peripheral} The touch sensor. * @alias ev3_touchSensor4 */ -var touchSensor4 = function() { -}; +var touchSensor4 = function () {} /** * Gets whether the touch sensor is pressed. @@ -274,8 +248,7 @@ var touchSensor4 = function() { * @returns {boolean} true when the touch sensor is pressed, false otherwise. * @alias ev3_touchSensorPressed */ -var touchSensorPressed = function(touchSensor) { -}; +var touchSensorPressed = function (touchSensor) {} /** * Gets the ultrasonic sensor connected any of ports 1, 2, 3 or 4. @@ -283,8 +256,7 @@ var touchSensorPressed = function(touchSensor) { * @returns {peripheral} The ultrasonic sensor. * @alias ev3_ultrasonicSensor */ -var ultrasonicSensor = function() { -}; +var ultrasonicSensor = function () {} /** * Gets the distance read by the ultrasonic sensor in centimeters. @@ -293,8 +265,7 @@ var ultrasonicSensor = function() { * @returns {number} The distance, in centimeters. * @alias ev3_ultrasonicSensorDistance */ -var ultrasonicSensorDistance = function(ultrasonicSensor) { -}; +var ultrasonicSensorDistance = function (ultrasonicSensor) {} /** * Gets the gyro sensor connected any of ports 1, 2, 3 or 4. @@ -302,8 +273,7 @@ var ultrasonicSensorDistance = function(ultrasonicSensor) { * @returns {peripheral} The gyro sensor. * @alias ev3_gyroSensor */ -var gyroSensor = function() { -}; +var gyroSensor = function () {} /** * Gets the rate of rotation detected by the gyro sensor. @@ -312,8 +282,7 @@ var gyroSensor = function() { * @returns {number} The rate of rotation, in degrees per second. * @alias ev3_gyroSensorRate */ -var gyroSensorRate = function(gyroSensor) { -}; +var gyroSensorRate = function (gyroSensor) {} /** * Gets the absolute angle detected by the gyro sensor, measured from when @@ -323,9 +292,7 @@ var gyroSensorRate = function(gyroSensor) { * @returns {number} The angle, in degrees. * @alias ev3_gyroSensorAngle */ -var gyroSensorAngle = function(gyroSensor) { -}; - +var gyroSensorAngle = function (gyroSensor) {} /** * Pauses for a period of time. @@ -333,8 +300,7 @@ var gyroSensorAngle = function(gyroSensor) { * @param {number} time - The time to wait, in milliseconds. * @alias ev3_pause */ -var pause = function(time) { -}; +var pause = function (time) {} /** * Returns a hello world message. @@ -342,7 +308,7 @@ var pause = function(time) { * @returns {string} A hello world message. * @alias ev3_hello */ -var hello = function() {}; +var hello = function () {} /** * Waits for one of the buttons on the EV3's control face to be pressed, then @@ -358,7 +324,7 @@ var hello = function() {}; * @returns {number} A number corresponding to the button that was pressed * @alias ev3_waitForButtonPress */ -var waitForButtonPress = function() {}; +var waitForButtonPress = function () {} /** * Makes the robot speak the given words through its speaker. Returns after the @@ -367,7 +333,7 @@ var waitForButtonPress = function() {}; * @param {string} words - The words to speak. * @alias ev3_speak */ -var speak = function(words) {}; +var speak = function (words) {} /** * Causes the robot to emit a sequence of beeps. Returns after the beeps are @@ -381,7 +347,7 @@ var speak = function(words) {}; * @param {Array} beeps - The beep sequence. * @alias ev3_playSequence */ -var playSequence = function(beeps) {}; +var playSequence = function (beeps) {} /** * Gets the left green LED. @@ -393,7 +359,7 @@ var playSequence = function(beeps) {}; * @returns {peripheral} The left green LED * @alias ev3_ledLeftGreen */ -var ledLeftGreen = function() {}; +var ledLeftGreen = function () {} /** * Gets the left red LED. @@ -405,7 +371,7 @@ var ledLeftGreen = function() {}; * @returns {peripheral} The left red LED * @alias ev3_ledLeftRed */ -var ledLeftRed = function() {}; +var ledLeftRed = function () {} /** * Gets the right green LED. @@ -417,7 +383,7 @@ var ledLeftRed = function() {}; * @returns {peripheral} The right green LED * @alias ev3_ledRightGreen */ -var ledRightGreen = function() {}; +var ledRightGreen = function () {} /** * Gets the right red LED. @@ -429,7 +395,7 @@ var ledRightGreen = function() {}; * @returns {peripheral} The right red LED * @alias ev3_ledRightRed */ -var ledRightRed = function() {}; +var ledRightRed = function () {} /** * Gets the brightness of the given LED. @@ -440,7 +406,7 @@ var ledRightRed = function() {}; * @returns {number} The brightness of the given LED * @alias ev3_ledGetBrightness */ -var ledGetBrightness = function (led) {}; +var ledGetBrightness = function (led) {} /** * Sets the brightness of the given LED. @@ -451,4 +417,4 @@ var ledGetBrightness = function (led) {}; * @param {number} brightness - The desired brightness * @alias ev3_ledSetBrightness */ -var ledSetBrightness = function (led, brightness) {}; +var ledSetBrightness = function (led, brightness) {} diff --git a/docs/lib/list.js b/docs/lib/list.js index 68be4f23c..dfeac7993 100644 --- a/docs/lib/list.js +++ b/docs/lib/list.js @@ -8,7 +8,7 @@ * @returns {pair} pair with x as head and y as tail. */ function pair(x, y) {} - + /** * **primitive**; returns true if x is a * pair and false otherwise; time: Theta(1)Theta(1). @@ -23,7 +23,7 @@ function is_pair(x) {} * @returns {value} head of p */ function head(p) {} - + /** * **primitive**; returns tail (second component of given pair p; time: Theta(1)Theta(1). * @param {pair} p - given pair @@ -38,13 +38,13 @@ function tail(p) {} * @returns {boolean} whether x is null */ function is_null(x) {} - + /** * **primitive**; returns true if * xs is a list as defined in the textbook, and - * false otherwise. Iterative process; + * false otherwise. Iterative process; * time: Theta(n), space: Theta(1), where n - * is the length of the + * is the length of the * chain of tail operations that can be applied to xs. * is_list recurses down the list and checks that it ends with the empty list null * @param {value} xs - given candidate @@ -58,7 +58,7 @@ function is_list(xs) {} * @param {value} value1,value2,...,value_n - given values * @returns {list} list containing all values */ -function list(value1, value2, ...values ) {} +function list(value1, value2, ...values) {} /** * visualizes the arguments in a separate drawing @@ -68,14 +68,14 @@ function list(value1, value2, ...values ) {} * @param {value} value1,value2,...,value_n - given values * @returns {value} given x */ - function draw_data(value1, value2, ...values ) {} +function draw_data(value1, value2, ...values) {} /** * Returns true if both * have the same structure with respect to pair, - * and identical values at corresponding leave positions (places that are not + * and identical values at corresponding leave positions (places that are not * themselves pairs), and false otherwise. For the "identical", - * the values need to have the same type, otherwise the result is + * the values need to have the same type, otherwise the result is * false. If corresponding leaves are boolean values, these values * need to be the same. If both are undefined or both are * null, the result is true. Otherwise they are compared @@ -89,61 +89,56 @@ function list(value1, value2, ...values ) {} * @returns {boolean} whether x is structurally equal to y */ function equal(xs, ys) { - return is_pair(xs) - ? (is_pair(ys) && - equal(head(xs), head(ys)) && - equal(tail(xs), tail(ys))) - : is_null(xs) - ? is_null(ys) - : is_number(xs) - ? (is_number(ys) && xs === ys) + return is_pair(xs) + ? is_pair(ys) && equal(head(xs), head(ys)) && equal(tail(xs), tail(ys)) + : is_null(xs) + ? is_null(ys) + : is_number(xs) + ? is_number(ys) && xs === ys : is_boolean(xs) - ? (is_boolean(ys) && ((xs && ys) || (!xs && !ys))) - : is_string(xs) - ? (is_string(ys) && xs === ys) - : is_undefined(xs) - ? is_undefined(ys) - : // we know now that xs is a function - (is_function(ys) && xs === ys); + ? is_boolean(ys) && ((xs && ys) || (!xs && !ys)) + : is_string(xs) + ? is_string(ys) && xs === ys + : is_undefined(xs) + ? is_undefined(ys) + : // we know now that xs is a function + is_function(ys) && xs === ys } /** * Returns the length of the list - * xs. + * xs. * Iterative process; time: Theta(n), space: * Theta(1), where n is the length of xs. * @param {list} xs - given list * @returns {number} length of xs */ function length(xs) { - return $length(xs, 0); + return $length(xs, 0) } function $length(xs, acc) { - return is_null(xs) ? acc : $length(tail(xs), acc + 1); + return is_null(xs) ? acc : $length(tail(xs), acc + 1) } /** * Returns a list that results from list - * xs by element-wise application of unary function f. + * xs by element-wise application of unary function f. * Iterative process; time: Theta(n) (apart from f), * space: Theta(n) (apart from f), where n is the length of xs. * f is applied element-by-element: * map(f, list(1, 2)) results in list(f(1), f(2)). - * @param {function} f - unary + * @param {function} f - unary * @param {list} xs - given list * @returns {list} result of mapping */ function map(f, xs) { - return $map(f, xs, null); + return $map(f, xs, null) } function $map(f, xs, acc) { - return is_null(xs) - ? reverse(acc) - : $map(f, tail(xs), pair(f(head(xs)), acc)); + return is_null(xs) ? reverse(acc) : $map(f, tail(xs), pair(f(head(xs)), acc)) } - -/** +/** * Makes a list with n * elements by applying the unary function f * to the numbers 0 to n - 1, assumed to be a nonnegative integer. @@ -153,10 +148,10 @@ function $map(f, xs, acc) { * @returns {list} resulting list */ function build_list(fun, n) { - return $build_list(n - 1, fun, null); + return $build_list(n - 1, fun, null) } function $build_list(i, fun, already_built) { - return i < 0 ? already_built : $build_list(i - 1, fun, pair(fun(i), already_built)); + return i < 0 ? already_built : $build_list(i - 1, fun, pair(fun(i), already_built)) } /** @@ -167,21 +162,20 @@ function $build_list(i, fun, already_built) { * f is applied element-by-element: * for_each(fun, list(1, 2)) results in the calls * fun(1) and fun(2). - * @param {function} f - unary + * @param {function} f - unary * @param {list} xs - given list * @returns {boolean} true */ function for_each(fun, xs) { if (is_null(xs)) { - return true; + return true } else { - fun(head(xs)); - return for_each(fun, tail(xs)); + fun(head(xs)) + return for_each(fun, tail(xs)) } } - /** * Returns a string that represents * list xs using the text-based box-and-pointer notation @@ -193,18 +187,16 @@ function for_each(fun, xs) { * @returns {string} xs converted to string */ function list_to_string(xs) { - return $list_to_string(xs, x => x); + return $list_to_string(xs, x => x) } function $list_to_string(xs, cont) { - return is_null(xs) - ? cont("null") - : is_pair(xs) - ? $list_to_string( - head(xs), - x => $list_to_string( - tail(xs), - y => cont("[" + x + "," + y + "]"))) - : cont(stringify(xs)); + return is_null(xs) + ? cont('null') + : is_pair(xs) + ? $list_to_string(head(xs), x => + $list_to_string(tail(xs), y => cont('[' + x + ',' + y + ']')) + ) + : cont(stringify(xs)) } /** @@ -217,16 +209,14 @@ function $list_to_string(xs, cont) { * @returns {list} xs in reverse */ function reverse(xs) { - return $reverse(xs, null); + return $reverse(xs, null) } function $reverse(original, reversed) { - return is_null(original) - ? reversed - : $reverse(tail(original), pair(head(original), reversed)); + return is_null(original) ? reversed : $reverse(tail(original), pair(head(original), reversed)) } /** - * Returns a list that results from + * Returns a list that results from * appending the list ys to the list xs. * Iterative process; time: Theta(n), space: * Theta(n), where n is the length of xs. @@ -238,12 +228,10 @@ function $reverse(original, reversed) { * @returns {list} result of appending xs and ys */ function append(xs, ys) { - return $append(xs, ys, xs => xs); + return $append(xs, ys, xs => xs) } function $append(xs, ys, cont) { - return is_null(xs) - ? cont(ys) - : $append(tail(xs), ys, zs => cont(pair(head(xs), zs))); + return is_null(xs) ? cont(ys) : $append(tail(xs), ys, zs => cont(pair(head(xs), zs))) } /** @@ -258,11 +246,7 @@ function $append(xs, ys, cont) { * @returns {list} postfix sublist that starts with v */ function member(v, xs) { - return is_null(xs) - ? null - : (v === head(xs)) - ? xs - : member(v, tail(xs)); + return is_null(xs) ? null : v === head(xs) ? xs : member(v, tail(xs)) } /** Returns a list that results from @@ -277,14 +261,14 @@ function member(v, xs) { * @returns {list} xs with first occurrence of v removed */ function remove(v, xs) { - return $remove(v, xs, null); + return $remove(v, xs, null) } function $remove(v, xs, acc) { return is_null(xs) - ? append(reverse(acc), xs) - : v === head(xs) - ? append(reverse(acc), tail(xs)) - : $remove(v, tail(xs), pair(head(xs), acc)); + ? append(reverse(acc), xs) + : v === head(xs) + ? append(reverse(acc), tail(xs)) + : $remove(v, tail(xs), pair(head(xs), acc)) } /** @@ -292,7 +276,7 @@ function $remove(v, xs, acc) { * xs by removing all items from xs that * are identical (===) to v. * Returns the original - * list if there is no occurrence. + * list if there is no occurrence. * Iterative process; * time: Theta(n), space: Theta(n), where n * is the length of xs. @@ -301,14 +285,14 @@ function $remove(v, xs, acc) { * @returns {list} xs with all occurrences of v removed */ function remove_all(v, xs) { - return $remove_all(v, xs, null); + return $remove_all(v, xs, null) } function $remove_all(v, xs, acc) { return is_null(xs) - ? append(reverse(acc), xs) - : v === head(xs) - ? $remove_all(v, tail(xs), acc) - : $remove_all(v, tail(xs), pair(head(xs), acc)); + ? append(reverse(acc), xs) + : v === head(xs) + ? $remove_all(v, tail(xs), acc) + : $remove_all(v, tail(xs), pair(head(xs), acc)) } /** @@ -324,14 +308,14 @@ function $remove_all(v, xs, acc) { * @returns {list} list with those elements of xs for which pred holds. */ function filter(pred, xs) { - return $filter(pred, xs, null); + return $filter(pred, xs, null) } function $filter(pred, xs, acc) { return is_null(xs) ? reverse(acc) : pred(head(xs)) - ? $filter(pred, tail(xs), pair(head(xs), acc)) - : $filter(pred, tail(xs), acc); + ? $filter(pred, tail(xs), pair(head(xs), acc)) + : $filter(pred, tail(xs), acc) } /** @@ -346,17 +330,15 @@ function $filter(pred, xs, acc) { * @returns {list} list from start to end */ function enum_list(start, end) { - return $enum_list(start, end, null); + return $enum_list(start, end, null) } function $enum_list(start, end, acc) { - return start > end - ? reverse(acc) - : $enum_list(start + 1, end, pair(start, acc)); + return start > end ? reverse(acc) : $enum_list(start + 1, end, pair(start, acc)) } -/** +/** * Returns the element - * of list xs at position n, + * of list xs at position n, * where the first element has index 0. * Iterative process; * time: Theta(n), space: Theta(1), @@ -366,16 +348,14 @@ function $enum_list(start, end, acc) { * @returns {value} item in xs at position n */ function list_ref(xs, n) { - return n === 0 - ? head(xs) - : list_ref(tail(xs), n - 1); + return n === 0 ? head(xs) : list_ref(tail(xs), n - 1) } /** Applies binary * function f to the elements of xs from * right-to-left order, first applying f to the last element * and the value initial, resulting in r1, - * then to the + * then to the * second-last element and r1, resulting in * r2, * etc, and finally @@ -392,15 +372,12 @@ function list_ref(xs, n) { * @returns {value} result of accumulating xs using f starting with initial */ function accumulate(f, initial, xs) { - return $accumulate(f, initial, xs, x => x); + return $accumulate(f, initial, xs, x => x) } function $accumulate(f, initial, xs, cont) { - return is_null(xs) - ? cont(initial) - : $accumulate(f, initial, tail(xs), x => cont(f(head(xs), x))); + return is_null(xs) ? cont(initial) : $accumulate(f, initial, tail(xs), x => cont(f(head(xs), x))) } - /** * Optional second argument. * Similar to display, but formats well-formed lists nicely if detected; diff --git a/docs/lib/math.js b/docs/lib/math.js index 068ec86fd..5696f4bdb 100644 --- a/docs/lib/math.js +++ b/docs/lib/math.js @@ -1,30 +1,28 @@ /** - * + * * The Number value for e, Euler's number, * which is approximately 2.718281828459045. * @const {number} - * + * */ -const math_E = 2.718281828459045; - +const math_E = 2.718281828459045 /** - * - * The Number value for the natural logarithm of 10, + * + * The Number value for the natural logarithm of 10, * which is approximately 2.302585092994046. * @const {number} - * + * */ -const math_LN10 = 2.302585092994046; +const math_LN10 = 2.302585092994046 - -/** - * The Number value for the natural logarithm of 2, +/** + * The Number value for the natural logarithm of 2, * which is approximately 0.6931471805599453. * @const {number} - * + * */ -const math_LN2 = 0.6931471805599453; +const math_LN2 = 0.6931471805599453 /** * The Number value for the base-10 logarithm of e, @@ -35,7 +33,7 @@ the base of the natural logarithms; this value is approximately 0.43429448190325 * * @const {number} */ -const math_LOG10E = 1 / math_LN10; +const math_LOG10E = 1 / math_LN10 /** * The Number value for the base-2 logarithm of eℝ, the base of the natural logarithms; @@ -46,7 +44,7 @@ this value is approximately 1.4426950408889634. * * @const {number} */ -const math_LOG2E = 1 / math_LN2; +const math_LOG2E = 1 / math_LN2 /** * The Number value for π, the ratio of the circumference of a circle to its diameter, @@ -55,149 +53,139 @@ which is approximately 3.1415926535897932. * * @const {number} */ -const math_PI = 3.1415926535897932; +const math_PI = 3.1415926535897932 -/** +/** * The Number value for the square root of 2, which is approximately 1.4142135623730951. - * + * * @const {number} */ -const math_SQRT2 = 1.4142135623730951; +const math_SQRT2 = 1.4142135623730951 -/** +/** * The Number value for the square root of 0.5, which is approximately 0.7071067811865476. - * + * *

    NOTE: * The value of math_SQRT1_2 is approximately the reciprocal of the value of math_SQRT2. * @const {number} */ -const math_SQRT1_2 = 1 / math_SQRT2; +const math_SQRT1_2 = 1 / math_SQRT2 /** * * computes the absolute value of x; the result has the same magnitude as x but has positive sign. - * + * * @param {number} x - given number * @returns {number} absolute value of x -*/ -function math_abs( x ) {} + */ +function math_abs(x) {} /** - * computes the arc cosine of x. + * computes the arc cosine of x. * The result is expressed in radians and ranges from +0 to +π. - * + * * @param {number} x - given number * @returns {number} arc cosine of x */ -function math_acos( x ) {} +function math_acos(x) {} - /** * * computes the inverse hyperbolic cosine of x. - * + * * @param {number} x - given number * @returns {number} inverse hyperbolic cosine of x. */ -function math_acosh( x ) {} +function math_acosh(x) {} - /** * * computes the arc sine of x. The result is expressed in radians and ranges from -π / 2 to +π / 2. - * + * * @param {number} x - given number * @returns {number} arc sine of x. */ -function math_asin( x ) {} +function math_asin(x) {} - /** * - * computes the inverse hyperbolic + * computes the inverse hyperbolic * sine of x. The result is expressed in radians and ranges from -π / 2 to +π / 2. - * + * * @param {number} x - given number * @returns {number} inverse hyperbolic sine of x */ -function math_asinh( x ) {} +function math_asinh(x) {} - /** * * computes the arc tangent of x. The result is expressed in radians and ranges from -π / 2 to +π / 2. - * + * * @param {number} x - given number * @returns {number} arc tangent of x */ -function math_atan( x ) {} +function math_atan(x) {} - /** * * computes the inverse hyperbolic tangent of x. - * + * * @param {number} x - given number * @returns {number} inverse hyperbolic tangent of x. */ -function math_atanh( x ) {} +function math_atanh(x) {} - /** * * computes the arc tangent of the quotient y / x of the arguments y and x, where the signs of y and x are used to determine the quadrant of the result. Note that it is intentional and traditional for the two-argument arc tangent function that the argument named y be first and the argument named x be second. The result is expressed in radians and ranges from -π to +π. - * + * * @param {number} y - given first number * @param {number} x - given second number * @returns {number} arc tangent of y / x. */ -function math_atan2( y, x ) {} +function math_atan2(y, x) {} - /** * * computes the cube root of x. - * + * * @param {number} x - given number * @returns {number} cube root of x. */ -function math_cbrt( x ) {} +function math_cbrt(x) {} - /** * computes the smallest (closest to -∞) Number value that is not less than x and is an integer. If x is already an integer, the result is x. * The value of math_ceil(x) is the same as the value of -math_floor(-x). * @param {number} x - given number * @returns {number} "ceiling" of the number */ -function math_ceil( x ) {} +function math_ceil(x) {} - /** * When math_clz32 is called with one argument x, the following steps are taken: - * + * * Let n be ToUint32(x). * Let p be the number of leading zero bits in the 32-bit binary representation of n. * Return p. * *

    NOTE: - *
    If n is 0, p will be 32. If the most significant bit of the 32-bit binary encoding of n is 1, + *
    If n is 0, p will be 32. If the most significant bit of the 32-bit binary encoding of n is 1, * p will be 0. - * + * * @param {number} n - given number * @returns {number} p - leading zero bits */ -function math_clz32( x ) {} - +function math_clz32(x) {} /** * - * Computes the cosine of x. + * Computes the cosine of x. * The argument is expressed in radians. * @param {number} x - given number * @returns {number} - cosine of x */ -function math_cos( x ) {} +function math_cos(x) {} /** * @@ -207,47 +195,43 @@ function math_cos( x ) {} * @param { number } x - given number * @returns {number} hyperbolic cosine of x */ -function math_cosh( x ) {} +function math_cosh(x) {} - /** - * computes the exponential function of x + * computes the exponential function of x * (e raised to the power of x, where e is the base of the natural logarithms). - * + * * @param { number } x - given number * @returns {number} e to the power of x */ -function math_exp( x ) {} +function math_exp(x) {} - /** - * computes subtracting 1 from the - * exponential function of x (e raised to the power of x, where e is the base of - * the natural logarithms). The result is computed in a way that is accurate even + * computes subtracting 1 from the + * exponential function of x (e raised to the power of x, where e is the base of + * the natural logarithms). The result is computed in a way that is accurate even * when the value of x is close to 0. * @param {number} x - given number * @returns {number} -1 plus e to the power of x */ -function math_expm1( x ) {} +function math_expm1(x) {} - /** - * computes the greatest (closest to +∞) Number value that is not greater than x - * and is an integer. + * computes the greatest (closest to +∞) Number value that is not greater than x + * and is an integer. *
    If x is already an integer, the result is x. - * + * *

    NOTE: * The value of math_floor(x) is the same as the value of -math_ceil(-x). * @param {number} x - given number * @return {number} floor of x */ -function math_floor( x ) {} +function math_floor(x) {} - /** * * When math_fround is called with argument x, the following steps are taken: - * + * *

    1. If x is NaN, return NaN.
    2. *
    3. If x is one of +0, -0, +∞, -∞, return x.
    4. *
    5. Let x32 be the result of converting x to a value in IEEE 754-2008 binary32 format using roundTiesToEven mode.
    6. @@ -256,19 +240,19 @@ function math_floor( x ) {} * @param {number} x - given number * @returns {number} fround of x */ -function math_fround( x ) {} +function math_fround(x) {} /** - * + * * computes the square root * of the sum of squares of its arguments. - * + * *
      If no arguments are passed, the result is +0. * @param {number} value1,value2,... - given numbers * @returns {number} square root of sum of squares of arguments */ -function math_hypot ( value1, value2, ...values ) {} - +function math_hypot(value1, value2, ...values) {} + /** * * When math_imul is called with arguments x and y, @@ -282,178 +266,167 @@ function math_hypot ( value1, value2, ...values ) {} * @param {number} x - given second number * @returns {number} - x imul y */ -function math_imul( x, y ) {} +function math_imul(x, y) {} - /** * * Computes the natural logarithm of x. - * + * * @param {number} x - given number * @returns {number} - natural logarithm of x */ -function math_log ( x ) {} +function math_log(x) {} - /** * computes the natural logarithm of 1 + x. The result is computed in a way that is accurate even when the value of x is close to zero. * @param {number} x - given number * @returns {number} math_log(1 + x) */ -function math_log1p( x ) {} +function math_log1p(x) {} - /** * * computes the base 10 logarithm of x. * @param {number} x - given number * @returns {number} base 10 logarithm of x */ -function math_log10( x ) {} +function math_log10(x) {} - /** * * computes the base 2 logarithm of x. - * + * * @param {number} x - given number * @returns {number} base 2 logarithm of x */ -function math_log2( x ) {} +function math_log2(x) {} - /** * * Given zero or more numbers, returns the largest of them. - * + * *
      If no arguments are given, the result is -∞. *
      If any value is NaN, the result is NaN. - * The comparison of values to determine the largest value is done using the + * The comparison of values to determine the largest value is done using the * Abstract Relational Comparison algorithm except that +0 is considered to be larger than -0. * @param {number} value1,value2,... - given numbers * @returns {number} largest of them */ -function math_max( value1, value2, ...values ) {} - +function math_max(value1, value2, ...values) {} + /** * * Given zero or more arguments, returns the smallest of them. - * + * *
      If no arguments are given, the result is +∞. *
      If any value is NaN, the result is NaN. - * The comparison of values to determine the smallest value is done using the + * The comparison of values to determine the smallest value is done using the * Abstract Relational Comparison algorithm except that +0 is considered to be larger than -0. * @param {number} value1,value2,... - given numbers * @returns {number} smallest of them */ -function math_min( value1, value2, ...values ) {} - +function math_min(value1, value2, ...values) {} + /** * - * Computes the result of raising base to + * Computes the result of raising base to * the power of exponent. - * + * * @param {number} base - the given base * @param {number} exponent - the given exponent * @returns {number} base to the power of exponent **/ -function math_pow( base, exponent ) {} +function math_pow(base, exponent) {} - /** - * Returns a number value with positive sign, greater than or equal to 0 but less than 1, - * chosen randomly or pseudo randomly with approximately uniform distribution over that +/** + * Returns a number value with positive sign, greater than or equal to 0 but less than 1, + * chosen randomly or pseudo randomly with approximately uniform distribution over that * range, using an implementation-dependent algorithm or strategy. This function takes no arguments. - * - * Each math_random function created for distinct realms must produce a distinct sequence + * + * Each math_random function created for distinct realms must produce a distinct sequence * of values from successive calls. * @returns {number} random number greater than or equal to 0 but less than 1 */ -function math_random ( ) {} - +function math_random() {} + /** * - * Returns the number value that is closest to x and is an integer. - *
      If two integers are equally close to x, then the result is the Number value + * Returns the number value that is closest to x and is an integer. + *
      If two integers are equally close to x, then the result is the Number value * that is closer to +∞. If x is already an integer, the result is x. - * + * * NOTE 1: * math_round(3.5) returns 4, but math_round(-3.5) returns -3. * @param {number} x - the given number * @returns {number} closest integer to x */ -function math_round( x ) {} +function math_round(x) {} - /** * * Computes the sign of x, indicating whether x is positive, negative, or zero. - * + * * @param {number} x - the given number * @returns {number} the sign (-1, 0 or +1) */ -function math_sign( x ) {} - +function math_sign(x) {} + /** * - * Computes the sine of x. + * Computes the sine of x. * The argument is expressed in radians. * @param {number} x - the given number * @returns {number} the sine of x */ -function math_sin( x ) {} +function math_sin(x) {} - /** * * Computes the hyperbolic sine of x. *

      NOTE: * The value of sinh(x) is the same as (exp(x) - exp(-x)) / 2. - * + * * @param {number} x - the given number * @returns {number} the hyperbolic sine of x */ -function math_sinh( x ) {} +function math_sinh(x) {} - /** * * Computes the square root of x. - * + * * @param {number} x - the given number * @returns {number} the square root of x */ -function math_sqrt( x ) {} +function math_sqrt(x) {} - /** * * Computes the tangent of x. The argument is expressed in radians. - * + * * @param {number} x - the given number * @returns {number} the tangent of x */ -function math_tan( x ) {} +function math_tan(x) {} - /** * * Computes the hyperbolic tangent of x. - * + * *

      NOTE: * The value of math_tanh(x) is the same as * (exp(x) - exp(-x))/(exp(x) + exp(-x)). - * + * * @param {number} x - the given number * @returns {number} the hyperbolic tangent of x */ -function math_tanh( x ) {} +function math_tanh(x) {} - /** * * Computes the integral part of the number x, - * removing any fractional digits. + * removing any fractional digits. * @param {number} x - the given number * @returns {number} the integral part of x */ -function math_trunc( x ) {} +function math_trunc(x) {} diff --git a/docs/lib/mce.js b/docs/lib/mce.js index cedc31a97..6c28f88f9 100644 --- a/docs/lib/mce.js +++ b/docs/lib/mce.js @@ -1,8 +1,8 @@ /** * returns the parse tree that results from parsing * the string str as a Source program. The format - * of the parse tree is described in chapter 4 of - * the textbook + * of the parse tree is described in chapter 4 of + * the textbook * in Structure and * Interpretation of Computer Programs, JavaScript Adaptation (SICP). * @param {string} x - given program as a string @@ -28,4 +28,3 @@ function tokenize(str) {} * @returns {whatever} whatever f returns */ function apply_in_underlying_javascript(f, xs) {} - diff --git a/docs/lib/misc.js b/docs/lib/misc.js index d18c29377..73f8c1f56 100644 --- a/docs/lib/misc.js +++ b/docs/lib/misc.js @@ -4,16 +4,14 @@ * @param {value} v to be checked * @returns {boolean} indicating whether the value is a number */ -function is_number(v) { -} +function is_number(v) {} /** * checks whether a given value is a boolean * @param {value} v to be checked * @returns {boolean} indicating whether the value is a boolean */ -function is_boolean(v) { -} +function is_boolean(v) {} /** * checks whether a given value is a string. @@ -21,24 +19,21 @@ function is_boolean(v) { * @param {value} v to be checked * @returns {boolean} indicating whether the value is a string */ -function is_string(v) { -} +function is_string(v) {} /** * checks whether a given value is a function * @param {value} v to be checked * @returns {boolean} indicating whether the value is a function */ -function is_function(v) { -} +function is_function(v) {} /** * checks whether a given value is the special value undefined * @param {value} v to be checked * @returns {boolean} indicating whether the value is undefined */ -function is_undefined(v) { -} +function is_undefined(v) {} /** * Returns number of milliseconds elapsed since January 1, 1970 00:00:00 UTC. @@ -68,7 +63,7 @@ function parse_int(s, i) {} * See also textbook explanation in section 4.1.1. * @const {undefined} */ -const undefined = (() => {})(); +const undefined = (() => {})() /** * The name NaN refers to the special number value NaN ("not a number"). Note that @@ -76,14 +71,14 @@ const undefined = (() => {})(); * See ECMAScript Specification, Section 4.3.24 * @const {number} */ -const NaN = 0 / 0; +const NaN = 0 / 0 /** * The name Infinity refers to the special number value Infinity. * See ECMAScript Specification, Section 4.3.23 * @const {number} */ -const Infinity = 1 / 0; +const Infinity = 1 / 0 /** * Pops up a window that displays the string s, provides @@ -95,8 +90,7 @@ const Infinity = 1 / 0; * @param {string} s to be displayed in popup * @returns {string} entered text */ -function prompt(s) { -} +function prompt(s) {} /** * Optional second argument. If present, @@ -112,8 +106,7 @@ function prompt(s) { * @param {string} s to be displayed, preceding v, optional argument * @returns {value} v, the first argument value */ -function display(v, s) { -} +function display(v, s) {} /** * Optional second argument. @@ -131,8 +124,7 @@ function display(v, s) { * @param {value} v to be displayed * @param {string} s to be displayed, preceding v */ -function error(v, s) { -} +function error(v, s) {} /** * returns a string that represents the value v, using a @@ -143,8 +135,7 @@ function error(v, s) { * @param {value} v the argument value * @returns {string} string representation of v */ -function stringify(v) { -} +function stringify(v) {} /** * Takes a string s as first argument and a nonnegative integer @@ -165,5 +156,4 @@ function char_at(s, i) {} * @param {function} f - given function * @returns {number} number of parameters f expects */ - function arity(f) { - } +function arity(f) {} diff --git a/docs/lib/parsetreetypes.js b/docs/lib/parsetreetypes.js index acedfabc0..3d08a2827 100644 --- a/docs/lib/parsetreetypes.js +++ b/docs/lib/parsetreetypes.js @@ -4,7 +4,7 @@ // that is generated by the parse function in Source 4. // Program -type Program = Pair<"sequence", Pair, null>>; +type Program = Pair<'sequence', Pair, null>> // Statement type Statement = @@ -18,37 +18,40 @@ type Statement = | BreakStatement | ContinueStatement | Block - | Expression; + | Expression -type ConstantDeclaration = Pair<"constant_declaration", - Pair>>; -type FunctionDeclaration = Pair<"function_declaration", - Pair>>>; -type ReturnStatement = Pair<"return_statement", Pair>; -type WhileLoop = Pair<"while_loop", Pair>>; -type ForLoop = Pair<"for_loop", Pair>>>>; -type BreakStatement = Pair<"break_statement", null>; -type ContinueStatement = Pair<"continue_statement", null>; +type ConstantDeclaration = Pair<'constant_declaration', Pair>> +type FunctionDeclaration = Pair< + 'function_declaration', + Pair>> +> +type ReturnStatement = Pair<'return_statement', Pair> +type WhileLoop = Pair<'while_loop', Pair>> +type ForLoop = Pair< + 'for_loop', + Pair>>> +> +type BreakStatement = Pair<'break_statement', null> +type ContinueStatement = Pair<'continue_statement', null> // Parameters -type Parameters = List; +type Parameters = List // If-Statement -type ConditionalStatement = Pair<"conditional_statement", Pair>>>; +type ConditionalStatement = Pair< + 'conditional_statement', + Pair>> +> // Block -type Block = Pair<"block", Pair>; +type Block = Pair<'block', Pair> // Let -type VariableDeclaration = Pair<"variable_declaration", - Pair>>; +type VariableDeclaration = Pair<'variable_declaration', Pair>> // Assignment -type Assignment = Pair<"assignment", Pair>>; -type ObjectAssignment = Pair<"object_assignment", - Pair>>; +type Assignment = Pair<'assignment', Pair>> +type ObjectAssignment = Pair<'object_assignment', Pair>> // Expression type Expression = @@ -63,29 +66,34 @@ type Expression = | Assignment | ObjectAssignment | ObjectAccess - | ArrayExpression; + | ArrayExpression -type Literal = Pair<"literal", Pair>; -type Name = Pair<"name", Pair>; - type LogicalComposition = Pair<"logical_composition", Pair>>>; -type BinaryOperatorCombination = Pair<"binary_operator_combination", - Pair>>>; -type UnaryOperatorCombination = Pair<"unary_operator_combination", - Pair>>; -type Application = Pair<"application", Pair, null>>>; -type LambdaExpression = Pair<"lambda_expression", Pair>>; -type ConditionalExpression = Pair<"conditional_expression", Pair>>>; -type ObjectAccess = Pair<"object_access", Pair>>; -type ArrayExpression = Pair<"array_expression", Pair, null>>; +type Literal = Pair<'literal', Pair> +type Name = Pair<'name', Pair> +type LogicalComposition = Pair< + 'logical_composition', + Pair>> +> +type BinaryOperatorCombination = Pair< + 'binary_operator_combination', + Pair>> +> +type UnaryOperatorCombination = Pair< + 'unary_operator_combination', + Pair> +> +type Application = Pair<'application', Pair, null>>> +type LambdaExpression = Pair<'lambda_expression', Pair>> +type ConditionalExpression = Pair< + 'conditional_expression', + Pair>> +> +type ObjectAccess = Pair<'object_access', Pair>> +type ArrayExpression = Pair<'array_expression', Pair, null>> // Operators -type LogicalOperator = "&&" | "||"; -type BinaryOperator = "+" | "-" | "*" | "/" | "%" | "===" - | "!==" | "<" | ">" | "<=" | ">="; -type UnaryOperator = "!" | "-unary"; +type LogicalOperator = '&&' | '||' +type BinaryOperator = '+' | '-' | '*' | '/' | '%' | '===' | '!==' | '<' | '>' | '<=' | '>=' +type UnaryOperator = '!' | '-unary' // \end{lstlisting} // \texttt{parsetreetypes.js END} diff --git a/docs/lib/stream.js b/docs/lib/stream.js index c627f4318..25e45d6e1 100644 --- a/docs/lib/stream.js +++ b/docs/lib/stream.js @@ -6,30 +6,31 @@ /** * assumes that the tail (second component) of the * pair {x} is a nullary function, and returns the result of - * applying that function. Throws an exception if the argument + * applying that function. Throws an exception if the argument * is not a pair, or if the tail is not a function. - * Laziness: Yes: {stream_tail} only forces the direct tail - * stream, but not the rest of the stream, i.e. not the tail + * Laziness: Yes: {stream_tail} only forces the direct tail + * stream, but not the rest of the stream, i.e. not the tail * of the tail, etc. * @param {Stream} xs - given stream * @returns {Stream} result stream (if stream discipline is used) */ function stream_tail(xs) { - if (is_pair(xs)) { - const the_tail = tail(xs); - if (is_function(the_tail)) { - return the_tail(); - } else { - error(the_tail, - 'stream_tail(xs) expects a function as ' + - 'the tail of the argument pair xs, ' + - 'but encountered '); - } + if (is_pair(xs)) { + const the_tail = tail(xs) + if (is_function(the_tail)) { + return the_tail() } else { - error(xs, 'stream_tail(xs) expects a pair as ' + - 'argument xs, but encountered '); + error( + the_tail, + 'stream_tail(xs) expects a function as ' + + 'the tail of the argument pair xs, ' + + 'but encountered ' + ) } + } else { + error(xs, 'stream_tail(xs) expects a pair as ' + 'argument xs, but encountered ') + } } /** @@ -43,51 +44,43 @@ function stream_tail(xs) { */ function is_stream(xs) { - return is_null(xs) || - (is_pair(xs) && - is_function(tail(xs)) && - arity(tail(xs)) === 0 && - is_stream(stream_tail(xs))); + return ( + is_null(xs) || + (is_pair(xs) && is_function(tail(xs)) && arity(tail(xs)) === 0 && is_stream(stream_tail(xs))) + ) } /** * Given list xs, returns a stream of same length with * the same elements as xs in the same order. - * Laziness: Yes: list_to_stream - * goes down the list only when forced. + * Laziness: Yes: list_to_stream + * goes down the list only when forced. * @param {list} xs - given list * @returns {stream} stream containing all elements of xs */ function list_to_stream(xs) { - return is_null(xs) - ? null - : pair(head(xs), - () => list_to_stream(tail(xs))); + return is_null(xs) ? null : pair(head(xs), () => list_to_stream(tail(xs))) } /** * Given stream xs, returns a list of same length with * the same elements as xs in the same order. - * Laziness: No: stream_to_list needs to force the whole + * Laziness: No: stream_to_list needs to force the whole * stream. * @param {stream} xs - stream * @returns {list} containing all elements of xs */ function stream_to_list(xs) { - return is_null(xs) - ? null - : pair(head(xs), stream_to_list(stream_tail(xs))); + return is_null(xs) ? null : pair(head(xs), stream_to_list(stream_tail(xs))) } - - /** * Given n values, returns a stream of length n. * The elements of the stream are the given values in the given order. * Lazy? No: A - * complete list is generated, + * complete list is generated, * and then a stream using list_to_stream is generated from it. * @param {value} value1,value2,...,value_n - given values * @returns {stream} stream containing all values @@ -103,40 +96,35 @@ function stream() { /** * Returns the length of the stream - * xs. + * xs. * Iterative process. - * Lazy? No: The function needs to explore the whole stream + * Lazy? No: The function needs to explore the whole stream * @param {stream} xs - given stream * @returns {number} length of xs */ function stream_length(xs) { - return is_null(xs) - ? 0 - : 1 + stream_length(stream_tail(xs)); + return is_null(xs) ? 0 : 1 + stream_length(stream_tail(xs)) } /** * Returns a stream that results from stream - * xs by element-wise application - * of unary function f. + * xs by element-wise application + * of unary function f. * f is applied element-by-element: * stream_map(f, stream(1,2)) results in * the same as stream(f(1),f(2)). * Lazy? Yes: The argument stream is only explored as forced by * the result stream. - * @param {function} f - unary + * @param {function} f - unary * @param {stream} xs - given stream * @returns {stream} result of mapping */ function stream_map(f, s) { - return is_null(s) - ? null - : pair(f(head(s)), - () => stream_map(f, stream_tail(s))); + return is_null(s) ? null : pair(f(head(s)), () => stream_map(f, stream_tail(s))) } -/** +/** * Makes a stream with n * elements by applying the unary function f * to the numbers 0 to n - 1, assumed to be a nonnegative integer. @@ -148,16 +136,12 @@ function stream_map(f, s) { */ function build_stream(fun, n) { - function build(i) { - return i >= n - ? null - : pair(fun(i), - () => build(i + 1)); - } - return build(0); + function build(i) { + return i >= n ? null : pair(fun(i), () => build(i + 1)) + } + return build(0) } - /** * Applies unary function f to every * element of the stream xs. @@ -165,20 +149,20 @@ function build_stream(fun, n) { * f is applied element-by-element: * stream_for_each(f, stream(1, 2)) results in the calls * f(1) and f(2). - * Lazy? No: stream_for_each + * Lazy? No: stream_for_each * forces the exploration of the entire stream - * @param {function} f - unary + * @param {function} f - unary * @param {stream} xs - given stream * @returns {boolean} true */ function stream_for_each(fun, xs) { - if (is_null(xs)) { - return true; - } else { - fun(head(xs)); - return stream_for_each(fun, stream_tail(xs)); - } + if (is_null(xs)) { + return true + } else { + fun(head(xs)) + return stream_for_each(fun, stream_tail(xs)) + } } /** @@ -186,24 +170,26 @@ function stream_for_each(fun, xs) { * order. Iterative process. * The process is iterative, but consumes space Omega(n) * because of the result stream. - * Lazy? No: stream_reverse + * Lazy? No: stream_reverse * forces the exploration of the entire stream * @param {stream} xs - given stream * @returns {stream} xs in reverse */ function stream_reverse(xs) { - function rev(original, reversed) { - return is_null(original) - ? reversed - : rev(stream_tail(original), - pair(head(original), () => reversed)); - } - return rev(xs, null); + function rev(original, reversed) { + return is_null(original) + ? reversed + : rev( + stream_tail(original), + pair(head(original), () => reversed) + ) + } + return rev(xs, null) } /** - * Returns a stream that results from + * Returns a stream that results from * appending the stream ys to the stream xs. * In the result, null at the end of the first argument stream * is replaced by the second argument, regardless what the second @@ -215,10 +201,7 @@ function stream_reverse(xs) { */ function stream_append(xs, ys) { - return is_null(xs) - ? ys - : pair(head(xs), - () => stream_append(stream_tail(xs), ys)); + return is_null(xs) ? ys : pair(head(xs), () => stream_append(stream_tail(xs), ys)) } /** @@ -227,8 +210,8 @@ function stream_append(xs, ys) { * v (using ===); returns null if the * element does not occur in the stream. * Iterative process. - * Lazy? Sort-of: stream_member - * forces the stream only until the element + * Lazy? Sort-of: stream_member + * forces the stream only until the element * is found. * @param {value} v - given value * @param {stream} xs - given stream @@ -236,18 +219,14 @@ function stream_append(xs, ys) { */ function stream_member(x, s) { - return is_null(s) - ? null - : head(s) === x - ? s - : stream_member(x, stream_tail(s)); + return is_null(s) ? null : head(s) === x ? s : stream_member(x, stream_tail(s)) } /** Returns a stream that results from * xs by removing the first item from xs that * is identical (===) to v. * Returns the original - * stream if there is no occurrence. + * stream if there is no occurrence. * Lazy? Yes: the result stream forces the construction of each next element * @param {value} v - given value * @param {stream} xs - given stream @@ -255,12 +234,11 @@ function stream_member(x, s) { */ function stream_remove(v, xs) { - return is_null(xs) - ? null - : v === head(xs) - ? stream_tail(xs) - : pair(head(xs), - () => stream_remove(v, stream_tail(xs))); + return is_null(xs) + ? null + : v === head(xs) + ? stream_tail(xs) + : pair(head(xs), () => stream_remove(v, stream_tail(xs))) } /** @@ -268,21 +246,21 @@ function stream_remove(v, xs) { * xs by removing all items from xs that * are identical (===) to v. * Returns the original - * stream if there is no occurrence. + * stream if there is no occurrence. * Recursive process. - * Lazy? Yes: the result stream forces the construction of each next - * element + * Lazy? Yes: the result stream forces the construction of each next + * element * @param {value} v - given value * @param {stream} xs - given stream * @returns {stream} xs with all occurrences of v removed */ function stream_remove_all(v, xs) { - return is_null(xs) - ? null - : v === head(xs) - ? stream_remove_all(v, stream_tail(xs)) - : pair(head(xs), () => stream_remove_all(v, stream_tail(xs))); + return is_null(xs) + ? null + : v === head(xs) + ? stream_remove_all(v, stream_tail(xs)) + : pair(head(xs), () => stream_remove_all(v, stream_tail(xs))) } /** @@ -301,12 +279,11 @@ function stream_remove_all(v, xs) { */ function stream_filter(p, s) { - return is_null(s) - ? null - : p(head(s)) - ? pair(head(s), - () => stream_filter(p, stream_tail(s))) - : stream_filter(p, stream_tail(s)); + return is_null(s) + ? null + : p(head(s)) + ? pair(head(s), () => stream_filter(p, stream_tail(s))) + : stream_filter(p, stream_tail(s)) } /** @@ -321,14 +298,11 @@ function stream_filter(p, s) { */ function enum_stream(start, end) { - return start > end - ? null - : pair(start, - () => enum_stream(start + 1, end)); + return start > end ? null : pair(start, () => enum_stream(start + 1, end)) } /** - * Returns infinite stream if integers starting + * Returns infinite stream if integers starting * at given number n using a step size of 1. * Lazy? Yes: The result stream forces the construction of * each next element @@ -337,8 +311,7 @@ function enum_stream(start, end) { */ function integers_from(n) { - return pair(n, - () => integers_from(n + 1)); + return pair(n, () => integers_from(n + 1)) } /** @@ -353,20 +326,15 @@ function integers_from(n) { */ function eval_stream(s, n) { - function es(s, n) { - return n === 1 - ? list(head(s)) - : pair(head(s), - es(stream_tail(s), n - 1)); - } - return n === 0 - ? null - : es(s, n); + function es(s, n) { + return n === 1 ? list(head(s)) : pair(head(s), es(stream_tail(s), n - 1)) + } + return n === 0 ? null : es(s, n) } -/** +/** * Returns the element - * of stream xs at position n, + * of stream xs at position n, * where the first element has index 0. * Iterative process. * Lazy? Sort-of: stream_ref only forces the computation of @@ -378,9 +346,7 @@ function eval_stream(s, n) { */ function stream_ref(s, n) { - return n === 0 - ? head(s) - : stream_ref(stream_tail(s), n - 1); + return n === 0 ? head(s) : stream_ref(stream_tail(s), n - 1) } // \end{lstlisting} // \texttt{stream.js END} diff --git a/package.json b/package.json index 6a83ea103..51084069a 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,9 @@ "prepare": "husky install" }, "devDependencies": { + "@babel/core": "^7.26.10", "@babel/preset-env": "^7.23.2", + "@types/babel__core": "^7", "@types/jest": "^29.0.0", "@types/lodash": "^4.14.202", "@types/node": "^20.0.0", diff --git a/scripts/autocomplete.mjs b/scripts/autocomplete.mjs index 34de8e977..36b923b4b 100644 --- a/scripts/autocomplete.mjs +++ b/scripts/autocomplete.mjs @@ -1,36 +1,36 @@ // @ts-check -import fs from 'fs/promises'; -import pathlib from 'path'; -import { JSDOM } from 'jsdom'; +import fs from 'fs/promises' +import pathlib from 'path' +import { JSDOM } from 'jsdom' -const CONST_DECL = "const"; -const FUNC_DECL = "func"; +const CONST_DECL = 'const' +const FUNC_DECL = 'func' -const BASE_DIR = "docs/source" -const SRC_FILENAME = "global.html" -const OUT_DIR = "src/editors/ace/docTooltip" +const BASE_DIR = 'docs/source' +const SRC_FILENAME = 'global.html' +const OUT_DIR = 'src/editors/ace/docTooltip' const TARGETS = [ - "source_1", - "source_1_wasm", - "source_1_typed", - "source_2", - "source_2_typed", - "source_3", - "source_3_concurrent", - "source_3_typed", - "source_4", - "source_4_typed", - "source_4_explicit-control", - "External libraries" + 'source_1', + 'source_1_wasm', + 'source_1_typed', + 'source_2', + 'source_2_typed', + 'source_3', + 'source_3_concurrent', + 'source_3_typed', + 'source_4', + 'source_4_typed', + 'source_4_explicit-control', + 'External libraries' ] function newTitleNode(title, document) { - const node = document.createElement('h4'); - const text = document.createTextNode(title); - node.appendChild(text); - return node; + const node = document.createElement('h4') + const text = document.createTextNode(title) + node.appendChild(text) + return node } function buildDescriptionHtml(div) { @@ -38,63 +38,63 @@ function buildDescriptionHtml(div) { } function processConstant(namespace, element, document) { - const header = element.getElementsByTagName('h4')[0]; - const rawName = header.textContent; + const header = element.getElementsByTagName('h4')[0] + const rawName = header.textContent const fields = rawName.split(' ').slice(1) - let title = fields.join(''); - const name = header.getAttribute('id'); + let title = fields.join('') + const name = header.getAttribute('id') if (!title) { - title = name; + title = name } - const titleNode = newTitleNode(title, document); - const descriptionNode = element.getElementsByClassName('description')[0]; + const titleNode = newTitleNode(title, document) + const descriptionNode = element.getElementsByClassName('description')[0] - const descriptionDiv = document.createElement('div'); - descriptionDiv.appendChild(titleNode); - descriptionDiv.appendChild(descriptionNode); - const html = buildDescriptionHtml(descriptionDiv); + const descriptionDiv = document.createElement('div') + descriptionDiv.appendChild(titleNode) + descriptionDiv.appendChild(descriptionNode) + const html = buildDescriptionHtml(descriptionDiv) namespace[name] = { title, description: html, meta: CONST_DECL } } function processFunction(namespace, element, document) { - const header = element.getElementsByTagName('h4')[0]; - const title = header.textContent; - const name = header.getAttribute('id'); + const header = element.getElementsByTagName('h4')[0] + const title = header.textContent + const name = header.getAttribute('id') - const titleNode = newTitleNode(title, document); - const descriptionNode = element.getElementsByClassName('description')[0]; + const titleNode = newTitleNode(title, document) + const descriptionNode = element.getElementsByClassName('description')[0] - const descriptionDiv = document.createElement('div'); - descriptionDiv.appendChild(titleNode); - descriptionDiv.appendChild(descriptionNode); - const html = buildDescriptionHtml(descriptionDiv); + const descriptionDiv = document.createElement('div') + descriptionDiv.appendChild(titleNode) + descriptionDiv.appendChild(descriptionNode) + const html = buildDescriptionHtml(descriptionDiv) - namespace[name] = { title, description: html, meta: FUNC_DECL }; + namespace[name] = { title, description: html, meta: FUNC_DECL } } async function processDirGlobals(target) { - const inFile = pathlib.join(BASE_DIR, target, SRC_FILENAME); - let document; + const inFile = pathlib.join(BASE_DIR, target, SRC_FILENAME) + let document try { - const contents = await fs.readFile(inFile); - document = new JSDOM(contents.toString()).window.document; + const contents = await fs.readFile(inFile) + document = new JSDOM(contents.toString()).window.document } catch (err) { - console.error(inFile, "failed", err); - return err; + console.error(inFile, 'failed', err) + return err } - const names = {}; + const names = {} - const constants = document.getElementsByClassName("constant-entry"); - Array.prototype.forEach.call(constants, ele => processConstant(names, ele, document)); + const constants = document.getElementsByClassName('constant-entry') + Array.prototype.forEach.call(constants, ele => processConstant(names, ele, document)) const functions = document.getElementsByClassName('function-entry') - Array.prototype.forEach.call(functions, ele => processFunction(names, ele, document)); + Array.prototype.forEach.call(functions, ele => processFunction(names, ele, document)) - const outFile = pathlib.join(OUT_DIR, target + '.json'); + const outFile = pathlib.join(OUT_DIR, target + '.json') await fs.writeFile(outFile, JSON.stringify(names, null, 2), 'utf-8') return undefined } @@ -108,7 +108,7 @@ export default async function autocomplete() { console.error(` Error: path to jsdoc html is invalid. Ensure that this script is run from the project root and documentation has been generated\ - `); + `) } else { console.error(error) } @@ -116,11 +116,10 @@ export default async function autocomplete() { } await fs.mkdir(OUT_DIR, { recursive: true }) - + // Exit with error code if the there was some error const errors = await Promise.all(TARGETS.map(processDirGlobals)) if (errors.find(each => each !== undefined)) process.exit(1) console.log('Finished processing autocomplete documentation') } - diff --git a/scripts/docs.mjs b/scripts/docs.mjs index 70f0faef0..22ad7ac84 100644 --- a/scripts/docs.mjs +++ b/scripts/docs.mjs @@ -8,222 +8,178 @@ import process from 'process' import autocomplete from './autocomplete.mjs' const configs = { - "landing": { - "readme": "README_top.md", - "dst": "", - "libs": [ - "empty.js" - ] + landing: { + readme: 'README_top.md', + dst: '', + libs: ['empty.js'] }, - "Source §1": { - "readme": "README_1.md", - "dst": "source_1/", - "libs": [ - "misc.js", - "math.js" - ] + 'Source §1': { + readme: 'README_1.md', + dst: 'source_1/', + libs: ['misc.js', 'math.js'] }, - "Source §1 Typed": { - "readme": "README_1_TYPED.md", - "dst": "source_1_typed/", - "libs": [ - "misc.js", - "math.js" - ] + 'Source §1 Typed': { + readme: 'README_1_TYPED.md', + dst: 'source_1_typed/', + libs: ['misc.js', 'math.js'] }, - "Source §1 WebAssembly": { - "readme": "README_1_WASM.md", - "dst": "source_1_wasm/", - "libs": [ - "empty.js" - ] + 'Source §1 WebAssembly': { + readme: 'README_1_WASM.md', + dst: 'source_1_wasm/', + libs: ['empty.js'] }, - "Source §2": { - "readme": "README_2.md", - "dst": "source_2/", - "libs": [ - "auxiliary.js", - "misc.js", - "math.js", - "list.js" - ] + 'Source §2': { + readme: 'README_2.md', + dst: 'source_2/', + libs: ['auxiliary.js', 'misc.js', 'math.js', 'list.js'] }, - "Source §2 Typed": { - "readme": "README_2_TYPED.md", - "dst": "source_2_typed/", - "libs": [ - "auxiliary.js", - "misc.js", - "math.js", - "list.js" - ] + 'Source §2 Typed': { + readme: 'README_2_TYPED.md', + dst: 'source_2_typed/', + libs: ['auxiliary.js', 'misc.js', 'math.js', 'list.js'] }, - "Source §3": { - "readme": "README_3.md", - "dst": "source_3/", - "libs": [ - "auxiliary.js", - "misc.js", - "math.js", - "list.js", - "stream.js", - "array.js", - "pairmutator.js" + 'Source §3': { + readme: 'README_3.md', + dst: 'source_3/', + libs: [ + 'auxiliary.js', + 'misc.js', + 'math.js', + 'list.js', + 'stream.js', + 'array.js', + 'pairmutator.js' ] }, - "Source §3 Concurrent": { - "readme": "README_3_CONCURRENT.md", - "dst": "source_3_concurrent/", - "libs": [ - "auxiliary.js", - "misc.js", - "math.js", - "list.js", - "stream.js", - "array.js", - "pairmutator.js", - "concurrency.js" + 'Source §3 Concurrent': { + readme: 'README_3_CONCURRENT.md', + dst: 'source_3_concurrent/', + libs: [ + 'auxiliary.js', + 'misc.js', + 'math.js', + 'list.js', + 'stream.js', + 'array.js', + 'pairmutator.js', + 'concurrency.js' ] }, - "Source §3 Typed": { - "readme": "README_3_TYPED.md", - "dst": "source_3_typed/", - "libs": [ - "auxiliary.js", - "misc.js", - "math.js", - "list.js", - "stream.js", - "array.js", - "pairmutator.js" + 'Source §3 Typed': { + readme: 'README_3_TYPED.md', + dst: 'source_3_typed/', + libs: [ + 'auxiliary.js', + 'misc.js', + 'math.js', + 'list.js', + 'stream.js', + 'array.js', + 'pairmutator.js' ] }, - "Source §4": { - "readme": "README_4.md", - "dst": "source_4/", - "libs": [ - "auxiliary.js", - "misc.js", - "math.js", - "list.js", - "stream.js", - "array.js", - "pairmutator.js", - "mce.js" + 'Source §4': { + readme: 'README_4.md', + dst: 'source_4/', + libs: [ + 'auxiliary.js', + 'misc.js', + 'math.js', + 'list.js', + 'stream.js', + 'array.js', + 'pairmutator.js', + 'mce.js' ] }, - "Source §4 Explicit-Control": { - "readme": "README_4_EXPLICIT-CONTROL.md", - "dst": "source_4_explicit-control/", - "libs": [ - "auxiliary.js", - "misc.js", - "math.js", - "list.js", - "stream.js", - "array.js", - "pairmutator.js", - "mce.js", - "continuation.js" + 'Source §4 Explicit-Control': { + readme: 'README_4_EXPLICIT-CONTROL.md', + dst: 'source_4_explicit-control/', + libs: [ + 'auxiliary.js', + 'misc.js', + 'math.js', + 'list.js', + 'stream.js', + 'array.js', + 'pairmutator.js', + 'mce.js', + 'continuation.js' ] }, - "Source §4 Typed": { - "readme": "README_4_TYPED.md", - "dst": "source_4_typed/", - "libs": [ - "auxiliary.js", - "misc.js", - "math.js", - "list.js", - "stream.js", - "array.js", - "pairmutator.js", - "mce.js" + 'Source §4 Typed': { + readme: 'README_4_TYPED.md', + dst: 'source_4_typed/', + libs: [ + 'auxiliary.js', + 'misc.js', + 'math.js', + 'list.js', + 'stream.js', + 'array.js', + 'pairmutator.js', + 'mce.js' ] }, - "AUXILLARY": { - "readme": "README_AUXILIARY.md", - "dst": "AUXILIARY/", - "libs": [ - "auxiliary.js" - ] + AUXILLARY: { + readme: 'README_AUXILIARY.md', + dst: 'AUXILIARY/', + libs: ['auxiliary.js'] }, - "MISC": { - "readme": "README_MISC.md", - "dst": "MISC/", - "libs": [ - "misc.js" - ] + MISC: { + readme: 'README_MISC.md', + dst: 'MISC/', + libs: ['misc.js'] }, - "MATH": { - "readme": "README_MATH.md", - "dst": "MATH/", - "libs": [ - "math.js" - ] + MATH: { + readme: 'README_MATH.md', + dst: 'MATH/', + libs: ['math.js'] }, - "LIST": { - "readme": "README_LISTS.md", - "dst": "LISTS/", - "libs": [ - "list.js" - ] + LIST: { + readme: 'README_LISTS.md', + dst: 'LISTS/', + libs: ['list.js'] }, - "STREAMS": { - "readme": "README_STREAMS.md", - "dst": "STREAMS/", - "libs": [ - "stream.js" - ] + STREAMS: { + readme: 'README_STREAMS.md', + dst: 'STREAMS/', + libs: ['stream.js'] }, - "ARRAYS": { - "readme": "README_ARRAYS.md", - "dst": "ARRAYS/", - "libs": [ - "array.js" - ] + ARRAYS: { + readme: 'README_ARRAYS.md', + dst: 'ARRAYS/', + libs: ['array.js'] }, - "PAIRMUTATIONS": { - "readme": "README_PAIRMUTATORS.md", - "dst": "PAIRMUTATORS/", - "libs": [ - "pairmutator.js" - ] + PAIRMUTATIONS: { + readme: 'README_PAIRMUTATORS.md', + dst: 'PAIRMUTATORS/', + libs: ['pairmutator.js'] }, - "CONCURRENCY": { - "readme": "README_CONCURRENCY.md", - "dst": "CONCURRENCY/", - "libs": [ - "concurrency.js" - ] + CONCURRENCY: { + readme: 'README_CONCURRENCY.md', + dst: 'CONCURRENCY/', + libs: ['concurrency.js'] }, - "MCE": { - "readme": "README_MCE.md", - "dst": "MCE/", - "libs": [ - "mce.js" - ] + MCE: { + readme: 'README_MCE.md', + dst: 'MCE/', + libs: ['mce.js'] }, - "CONTINUATION": { - "readme": "README_CONTINUATION.md", - "dst": "CONTINUATION/", - "libs": [ - "continuation.js" - ] + CONTINUATION: { + readme: 'README_CONTINUATION.md', + dst: 'CONTINUATION/', + libs: ['continuation.js'] }, - "EV3": { - "readme": "EV3_README.md", - "dst": "EV3/", - "libs": [ - "ev3.js" - ] + EV3: { + readme: 'EV3_README.md', + dst: 'EV3/', + libs: ['ev3.js'] }, - "EXTERNAL": { - "readme": "README_EXTERNAL.md", - "dst": "External libraries", - "libs": [ - "ev3.js" - ] + EXTERNAL: { + readme: 'README_EXTERNAL.md', + dst: 'External libraries', + libs: ['ev3.js'] } } @@ -231,9 +187,9 @@ const config_file = 'docs/jsdoc/conf.json' const readmes = 'docs/md' const libraries = 'docs/lib' const out_dir = 'docs/source' -const jsdoc = "node_modules/jsdoc/jsdoc.js" -const template_location = "docs/jsdoc/templates/template" -const specs_dir = "docs/specs" +const jsdoc = 'node_modules/jsdoc/jsdoc.js' +const template_location = 'docs/jsdoc/templates/template' +const specs_dir = 'docs/specs' async function run() { await fs.mkdir(out_dir, { recursive: true }) @@ -243,10 +199,14 @@ async function run() { // for each configuration const proc = fork(jsdoc, [ '-r', - '-t', template_location, - '-c', config_file, - '-R', pathlib.join(readmes, config.readme), - '-d', pathlib.join(out_dir, config.dst), + '-t', + template_location, + '-c', + config_file, + '-R', + pathlib.join(readmes, config.readme), + '-d', + pathlib.join(out_dir, config.dst), ...config.libs.map(each => pathlib.join(libraries, each)) ]) @@ -280,19 +240,21 @@ async function prepare({ silent }) { await run() // Copy images in images directory to out_dir - await fs.readdir('docs/images') - .then(images => Promise.all(images.map(async img => { - const srcPath = pathlib.join('docs/images', img) - const dstPath = pathlib.join(out_dir, img) - await fs.copyFile(srcPath, dstPath) - console.debug(`Copied ${srcPath} to ${dstPath}`) - }))) + await fs.readdir('docs/images').then(images => + Promise.all( + images.map(async img => { + const srcPath = pathlib.join('docs/images', img) + const dstPath = pathlib.join(out_dir, img) + await fs.copyFile(srcPath, dstPath) + console.debug(`Copied ${srcPath} to ${dstPath}`) + }) + ) + ) - const makeProc = spawn('make', { cwd: specs_dir, stdio: [ - 'ignore', - silent ? 'ignore' : 'inherit', - 'inherit' - ]}) + const makeProc = spawn('make', { + cwd: specs_dir, + stdio: ['ignore', silent ? 'ignore' : 'inherit', 'inherit'] + }) const makeretcode = await new Promise(resolve => { makeProc.on('exit', resolve) @@ -306,16 +268,18 @@ async function prepare({ silent }) { console.log('Finished running make') // Copy pdf files that make produced to out_dir - await fs.readdir(specs_dir) - .then(files => Promise.all(files - .filter(file => pathlib.extname(file) === '.pdf') - .map(async file => { - const srcPath = pathlib.join(specs_dir, file) - const dstPath = pathlib.join(out_dir, file) - await fs.copyFile(srcPath, dstPath) - console.debug(`Copied ${srcPath} to ${dstPath}`) - }) - )) + await fs.readdir(specs_dir).then(files => + Promise.all( + files + .filter(file => pathlib.extname(file) === '.pdf') + .map(async file => { + const srcPath = pathlib.join(specs_dir, file) + const dstPath = pathlib.join(out_dir, file) + await fs.copyFile(srcPath, dstPath) + console.debug(`Copied ${srcPath} to ${dstPath}`) + }) + ) + ) } async function clean() { @@ -336,7 +300,8 @@ async function checkGitRoot() { } resolve(stdout.trim()) - })}) + }) + }) const procDir = pathlib.relative(gitRoot, '') if (procDir !== '') { @@ -347,22 +312,15 @@ async function checkGitRoot() { await new Command() .hook('preAction', checkGitRoot) - .addCommand( - new Command('run') - .description('Run JSDOC and build documentation') - .action(run), - { isDefault: true } - ) + .addCommand(new Command('run').description('Run JSDOC and build documentation').action(run), { + isDefault: true + }) .addCommand( new Command('prepare') .option('--silent', 'Run make without outputting to stdout') .action(prepare) ) - .addCommand( - new Command('clean') - .description('Clear the output directory') - .action(clean) - ) + .addCommand(new Command('clean').description('Clear the output directory').action(clean)) .addCommand( new Command('autocomplete') .description('Update autocomplete documentation') @@ -370,8 +328,7 @@ await new Command() ) .addCommand( new Command('docs') - .description('Execute the \'run\' command and then the \'autocomplete\' command') + .description("Execute the 'run' command and then the 'autocomplete' command") .action(() => run().then(autocomplete)) ) .parseAsync() - \ No newline at end of file diff --git a/src/cse-machine/__tests__/__snapshots__/cse-machine-errors.ts.snap b/src/cse-machine/__tests__/__snapshots__/cse-machine-errors.ts.snap index 5d412190e..a0dd4a136 100644 --- a/src/cse-machine/__tests__/__snapshots__/cse-machine-errors.ts.snap +++ b/src/cse-machine/__tests__/__snapshots__/cse-machine-errors.ts.snap @@ -1,5 +1,18 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Array access should have an array as object: expectParsedError 1`] = ` +Object { + "alertResult": Array [], + "code": "1[3];", + "displayResult": Array [], + "numErrors": 1, + "parsedErrors": "Line 1: Expected array, got number.", + "result": undefined, + "resultStatus": "error", + "visualiseListResult": Array [], +} +`; + exports[`Builtins don't create additional errors when it's not their fault: expectParsedError 1`] = ` Object { "alertResult": Array [], @@ -969,6 +982,20 @@ test();", } `; +exports[`Spread should have array as the argument: expectParsedError 1`] = ` +Object { + "alertResult": Array [], + "code": "const f = x => x; +f(...1);", + "displayResult": Array [], + "numErrors": 1, + "parsedErrors": "Line 2: Expected array, got number.", + "result": undefined, + "resultStatus": "error", + "visualiseListResult": Array [], +} +`; + exports[`Type error with * , error line at , not : expectParsedError 1`] = ` Object { "alertResult": Array [], diff --git a/src/cse-machine/__tests__/cse-machine-errors.ts b/src/cse-machine/__tests__/cse-machine-errors.ts index 9fa1bdc78..3b30703c9 100644 --- a/src/cse-machine/__tests__/cse-machine-errors.ts +++ b/src/cse-machine/__tests__/cse-machine-errors.ts @@ -60,6 +60,27 @@ test('Undefined variable error message differs from verbose version', () => { ) }) +const arrayaccessnotarray = stripIndent` +1[3]; +` + +test('Array access should have an array as object', () => { + return expectParsedError(arrayaccessnotarray, optionEC4).toMatchInlineSnapshot( + `"Line 1: Expected array, got number."` + ) +}) + +const spreadelementnotarray = stripIndent` +const f = x => x; +f(...1); +` + +test('Spread should have array as the argument', () => { + return expectParsedError(spreadelementnotarray, optionEC4).toMatchInlineSnapshot( + `"Line 2: Expected array, got number."` + ) +}) + const assignToBuiltin = stripIndent` map = 5; ` diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index 4615697c2..e8726d220 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -7,7 +7,7 @@ /* tslint:disable:max-classes-per-file */ import * as es from 'estree' -import { isArray, reverse } from 'lodash' +import { isArray } from 'lodash' import { IOptions } from '..' import { UNKNOWN_LOCATION } from '../constants' @@ -329,7 +329,7 @@ function evaluateImports(program: es.Program, context: Context) { * @returns The corresponding promise. */ export function CSEResultPromise(context: Context, value: Value): Promise { - return new Promise((resolve, reject) => { + return new Promise(resolve => { if (value instanceof CSEBreak) { resolve({ status: 'suspended-cse-eval', context }) } else if (value instanceof CseError) { @@ -560,12 +560,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { return }, - WhileStatement: function ( - command: es.WhileStatement, - context: Context, - control: Control, - stash: Stash - ) { + WhileStatement: function (command: es.WhileStatement, context: Context, control: Control) { if (hasBreakStatement(command.body as es.BlockStatement)) { control.push(instr.breakMarkerInstr(command)) } @@ -641,12 +636,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { } }, - IfStatement: function ( - command: es.IfStatement, - context: Context, - control: Control, - stash: Stash - ) { + IfStatement: function (command: es.IfStatement, context: Context, control: Control) { control.push(...reduceConditional(command)) }, @@ -714,21 +704,11 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { } }, - ContinueStatement: function ( - command: es.ContinueStatement, - context: Context, - control: Control, - stash: Stash - ) { + ContinueStatement: function (command: es.ContinueStatement, context: Context, control: Control) { control.push(instr.contInstr(command)) }, - BreakStatement: function ( - command: es.BreakStatement, - context: Context, - control: Control, - stash: Stash - ) { + BreakStatement: function (command: es.BreakStatement, context: Context, control: Control) { control.push(instr.breakInstr(command)) }, @@ -767,21 +747,15 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { ArrayExpression: function (command: es.ArrayExpression, context: Context, control: Control) { const elems = command.elements as ContiguousArrayElements - reverse(elems) const len = elems.length control.push(instr.arrLitInstr(len, command)) - for (const elem of elems) { - control.push(elem) + for (let i = len - 1; i >= 0; i--) { + control.push(elems[i]) } }, - MemberExpression: function ( - command: es.MemberExpression, - context: Context, - control: Control, - stash: Stash - ) { + MemberExpression: function (command: es.MemberExpression, context: Context, control: Control) { control.push(instr.arrAccInstr(command)) control.push(command.property) control.push(command.object) @@ -790,8 +764,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { ConditionalExpression: function ( command: es.ConditionalExpression, context: Context, - control: Control, - stash: Stash + control: Control ) { control.push(...reduceConditional(command)) }, @@ -854,7 +827,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { * Instructions */ - [InstrType.RESET]: function (command: Instr, context: Context, control: Control, stash: Stash) { + [InstrType.RESET]: function (command: Instr, context: Context, control: Control) { // Keep pushing reset instructions until marker is found. const cmdNext: ControlItem | undefined = control.pop() if (cmdNext && (!isInstr(cmdNext) || cmdNext.instrType !== InstrType.MARKER)) { @@ -1265,7 +1238,25 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { ) { const index = stash.pop() const array = stash.pop() - stash.push(array[index]) + + //Check if the index is legal + const indexRangeError = rttc.checkoutofRange(command.srcNode, index, context.chapter) + if (indexRangeError) { + handleRuntimeError(context, indexRangeError) + } + + // Check if left-hand side is array + const lhsArrayCheckError = rttc.checkArray(command.srcNode, array, context.chapter) + if (lhsArrayCheckError) { + handleRuntimeError(context, lhsArrayCheckError) + } + + // Check if index is out-of-bounds with array, in which case, returns undefined as per spec + if (index >= array.length) { + stash.push(undefined) + } else { + stash.push(array[index]) + } }, [InstrType.ARRAY_ASSIGNMENT]: function ( @@ -1281,12 +1272,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { stash.push(value) }, - [InstrType.CONTINUE]: function ( - command: Instr, - context: Context, - control: Control, - stash: Stash - ) { + [InstrType.CONTINUE]: function (command: Instr, context: Context, control: Control) { const next = control.pop() as ControlItem if (isInstr(next) && next.instrType == InstrType.CONTINUE_MARKER) { // Encountered continue mark, stop popping @@ -1301,7 +1287,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { [InstrType.CONTINUE_MARKER]: function () {}, - [InstrType.BREAK]: function (command: Instr, context: Context, control: Control, stash: Stash) { + [InstrType.BREAK]: function (command: Instr, context: Context, control: Control) { const next = control.pop() as ControlItem if (isInstr(next) && next.instrType == InstrType.BREAK_MARKER) { // Encountered break mark, stop popping @@ -1324,6 +1310,12 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { ) { const array = stash.pop() + // Check if right-hand side is array + const rhsArrayCheckError = rttc.checkArray(command.srcNode, array, context.chapter) + if (rhsArrayCheckError) { + handleRuntimeError(context, rhsArrayCheckError) + } + // spread array for (let i = 0; i < array.length; i++) { stash.push(array[i]) diff --git a/src/utils/rttc.ts b/src/utils/rttc.ts index 118177514..5803113f2 100644 --- a/src/utils/rttc.ts +++ b/src/utils/rttc.ts @@ -119,6 +119,13 @@ export const checkIfStatement = (node: Node, test: Value, chapter: Chapter = Cha : new TypeError(node, ' as condition', 'boolean', typeOf(test), chapter) } +const MAX_SOURCE_ARRAY_INDEX = 4294967295 +export const checkoutofRange = (node: Node, index: Value, chapter: Chapter = Chapter.SOURCE_4) => { + return index >= 0 && index <= MAX_SOURCE_ARRAY_INDEX // as per Source 3 spec + ? undefined + : new TypeError(node, ' in reasonable range', 'index', 'out of range', chapter) +} + export const checkMemberAccess = (node: Node, obj: Value, prop: Value) => { if (isObject(obj)) { return isString(prop) ? undefined : new TypeError(node, ' as prop', 'string', typeOf(prop)) @@ -136,3 +143,9 @@ export const checkMemberAccess = (node: Node, obj: Value, prop: Value) => { export const isIdentifier = (node: any): node is es.Identifier => { return (node as es.Identifier).name !== undefined } + +export const checkArray = (node: Node, maybeArray: Value, chapter: Chapter = Chapter.SOURCE_4) => { + return isArray(maybeArray) + ? undefined + : new TypeError(node, '', 'array', typeOf(maybeArray), chapter) +} diff --git a/yarn.lock b/yarn.lock index 2bbef2041..112755624 100644 --- a/yarn.lock +++ b/yarn.lock @@ -32,6 +32,17 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.26.2": + version: 7.26.2 + resolution: "@babel/code-frame@npm:7.26.2" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.25.9" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10c0/7d79621a6849183c415486af99b1a20b84737e8c11cd55b6544f688c51ce1fd710e6d869c3dd21232023da272a79b91efb3e83b5bc2dc65c1187c5fcd1b72ea8 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9, @babel/compat-data@npm:^7.23.2, @babel/compat-data@npm:^7.23.5": version: 7.23.5 resolution: "@babel/compat-data@npm:7.23.5" @@ -39,6 +50,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.26.5": + version: 7.26.8 + resolution: "@babel/compat-data@npm:7.26.8" + checksum: 10c0/66408a0388c3457fff1c2f6c3a061278dd7b3d2f0455ea29bb7b187fa52c60ae8b4054b3c0a184e21e45f0eaac63cf390737bc7504d1f4a088a6e7f652c068ca + languageName: node + linkType: hard + "@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3": version: 7.23.9 resolution: "@babel/core@npm:7.23.9" @@ -62,6 +80,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.26.10": + version: 7.26.10 + resolution: "@babel/core@npm:7.26.10" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.26.2" + "@babel/generator": "npm:^7.26.10" + "@babel/helper-compilation-targets": "npm:^7.26.5" + "@babel/helper-module-transforms": "npm:^7.26.0" + "@babel/helpers": "npm:^7.26.10" + "@babel/parser": "npm:^7.26.10" + "@babel/template": "npm:^7.26.9" + "@babel/traverse": "npm:^7.26.10" + "@babel/types": "npm:^7.26.10" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/e046e0e988ab53841b512ee9d263ca409f6c46e2a999fe53024688b92db394346fa3aeae5ea0866331f62133982eee05a675d22922a4603c3f603aa09a581d62 + languageName: node + linkType: hard + "@babel/generator@npm:^7.23.6, @babel/generator@npm:^7.7.2": version: 7.23.6 resolution: "@babel/generator@npm:7.23.6" @@ -74,6 +115,19 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.26.10": + version: 7.26.10 + resolution: "@babel/generator@npm:7.26.10" + dependencies: + "@babel/parser": "npm:^7.26.10" + "@babel/types": "npm:^7.26.10" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^3.0.2" + checksum: 10c0/88b3b3ea80592fc89349c4e1a145e1386e4042866d2507298adf452bf972f68d13bf699a845e6ab8c028bd52c2247013eb1221b86e1db5c9779faacba9c4b10e + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" @@ -105,6 +159,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/helper-compilation-targets@npm:7.26.5" + dependencies: + "@babel/compat-data": "npm:^7.26.5" + "@babel/helper-validator-option": "npm:^7.25.9" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10c0/9da5c77e5722f1a2fcb3e893049a01d414124522bbf51323bb1a0c9dcd326f15279836450fc36f83c9e8a846f3c40e88be032ed939c5a9840922bed6073edfb4 + languageName: node + linkType: hard + "@babel/helper-create-class-features-plugin@npm:^7.22.11, @babel/helper-create-class-features-plugin@npm:^7.22.5": version: 7.22.15 resolution: "@babel/helper-create-class-features-plugin@npm:7.22.15" @@ -196,6 +263,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-module-imports@npm:7.25.9" + dependencies: + "@babel/traverse": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10c0/078d3c2b45d1f97ffe6bb47f61961be4785d2342a4156d8b42c92ee4e1b7b9e365655dd6cb25329e8fe1a675c91eeac7e3d04f0c518b67e417e29d6e27b6aa70 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.22.5, @babel/helper-module-transforms@npm:^7.23.0, @babel/helper-module-transforms@npm:^7.23.3": version: 7.23.3 resolution: "@babel/helper-module-transforms@npm:7.23.3" @@ -211,6 +288,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/helper-module-transforms@npm:7.26.0" + dependencies: + "@babel/helper-module-imports": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/ee111b68a5933481d76633dad9cdab30c41df4479f0e5e1cc4756dc9447c1afd2c9473b5ba006362e35b17f4ebddd5fca090233bef8dfc84dca9d9127e56ec3a + languageName: node + linkType: hard + "@babel/helper-optimise-call-expression@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" @@ -301,6 +391,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-option@npm:7.25.9" + checksum: 10c0/27fb195d14c7dcb07f14e58fe77c44eea19a6a40a74472ec05c441478fa0bb49fa1c32b2d64be7a38870ee48ef6601bdebe98d512f0253aea0b39756c4014f3e + languageName: node + linkType: hard + "@babel/helper-wrap-function@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-wrap-function@npm:7.22.20" @@ -323,6 +420,16 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.26.10": + version: 7.26.10 + resolution: "@babel/helpers@npm:7.26.10" + dependencies: + "@babel/template": "npm:^7.26.9" + "@babel/types": "npm:^7.26.10" + checksum: 10c0/f99e1836bcffce96db43158518bb4a24cf266820021f6461092a776cba2dc01d9fc8b1b90979d7643c5c2ab7facc438149064463a52dd528b21c6ab32509784f + languageName: node + linkType: hard + "@babel/highlight@npm:^7.23.4": version: 7.23.4 resolution: "@babel/highlight@npm:7.23.4" @@ -343,6 +450,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.26.10, @babel/parser@npm:^7.26.9": + version: 7.26.10 + resolution: "@babel/parser@npm:7.26.10" + dependencies: + "@babel/types": "npm:^7.26.10" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/c47f5c0f63cd12a663e9dc94a635f9efbb5059d98086a92286d7764357c66bceba18ccbe79333e01e9be3bfb8caba34b3aaebfd8e62c3d5921c8cf907267be75 + languageName: node + linkType: hard + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.22.15": version: 7.22.15 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.22.15" @@ -1318,6 +1436,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.26.9": + version: 7.26.9 + resolution: "@babel/template@npm:7.26.9" + dependencies: + "@babel/code-frame": "npm:^7.26.2" + "@babel/parser": "npm:^7.26.9" + "@babel/types": "npm:^7.26.9" + checksum: 10c0/019b1c4129cc01ad63e17529089c2c559c74709d225f595eee017af227fee11ae8a97a6ab19ae6768b8aa22d8d75dcb60a00b28f52e9fa78140672d928bc1ae9 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.23.9": version: 7.23.9 resolution: "@babel/traverse@npm:7.23.9" @@ -1336,6 +1465,21 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.10": + version: 7.26.10 + resolution: "@babel/traverse@npm:7.26.10" + dependencies: + "@babel/code-frame": "npm:^7.26.2" + "@babel/generator": "npm:^7.26.10" + "@babel/parser": "npm:^7.26.10" + "@babel/template": "npm:^7.26.9" + "@babel/types": "npm:^7.26.10" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10c0/4e86bb4e3c30a6162bb91df86329df79d96566c3e2d9ccba04f108c30473a3a4fd360d9990531493d90f6a12004f10f616bf9b9229ca30c816b708615e9de2ac + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.6, @babel/types@npm:^7.23.9, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.26.9 resolution: "@babel/types@npm:7.26.9" @@ -1346,6 +1490,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.25.9, @babel/types@npm:^7.26.10, @babel/types@npm:^7.26.9": + version: 7.26.10 + resolution: "@babel/types@npm:7.26.10" + dependencies: + "@babel/helper-string-parser": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + checksum: 10c0/7a7f83f568bfc3dfabfaf9ae3a97ab5c061726c0afa7dcd94226d4f84a81559da368ed79671e3a8039d16f12476cf110381a377ebdea07587925f69628200dac + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -1720,6 +1874,17 @@ __metadata: languageName: node linkType: hard +"@jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.8 + resolution: "@jridgewell/gen-mapping@npm:0.3.8" + dependencies: + "@jridgewell/set-array": "npm:^1.2.1" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/c668feaf86c501d7c804904a61c23c67447b2137b813b9ce03eca82cb9d65ac7006d766c218685d76e3d72828279b6ee26c347aa1119dab23fbaf36aed51585a + languageName: node + linkType: hard + "@jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.2 resolution: "@jridgewell/resolve-uri@npm:3.1.2" @@ -1734,6 +1899,13 @@ __metadata: languageName: node linkType: hard +"@jridgewell/set-array@npm:^1.2.1": + version: 1.2.1 + resolution: "@jridgewell/set-array@npm:1.2.1" + checksum: 10c0/2a5aa7b4b5c3464c895c802d8ae3f3d2b92fcbe84ad12f8d0bfbb1f5ad006717e7577ee1fd2eac00c088abe486c7adb27976f45d2941ff6b0b92b2c3302c60f4 + languageName: node + linkType: hard + "@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" @@ -1751,6 +1923,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": + version: 0.3.25 + resolution: "@jridgewell/trace-mapping@npm:0.3.25" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10c0/3d1ce6ebc69df9682a5a8896b414c6537e428a1d68b02fcc8363b04284a8ca0df04d0ee3013132252ab14f2527bc13bea6526a912ecb5658f0e39fd2860b4df4 + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -1860,7 +2042,7 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.1.14": +"@types/babel__core@npm:^7, @types/babel__core@npm:^7.1.14": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" dependencies: @@ -2703,6 +2885,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.24.0": + version: 4.24.4 + resolution: "browserslist@npm:4.24.4" + dependencies: + caniuse-lite: "npm:^1.0.30001688" + electron-to-chromium: "npm:^1.5.73" + node-releases: "npm:^2.0.19" + update-browserslist-db: "npm:^1.1.1" + bin: + browserslist: cli.js + checksum: 10c0/db7ebc1733cf471e0b490b4f47e3e2ea2947ce417192c9246644e92c667dd56a71406cc58f62ca7587caf828364892e9952904a02b7aead752bc65b62a37cfe9 + languageName: node + linkType: hard + "bs-logger@npm:0.x": version: 0.2.6 resolution: "bs-logger@npm:0.2.6" @@ -2789,6 +2985,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001688": + version: 1.0.30001706 + resolution: "caniuse-lite@npm:1.0.30001706" + checksum: 10c0/b502d0a509611fd5b009e1123d482e983696984b6b749c3f485fd8d02cc58376c59cf0bb15f22fa2d337da104970edd27dd525d4663cebc728e26ac4adedff0d + languageName: node + linkType: hard + "caseless@npm:~0.12.0": version: 0.12.0 resolution: "caseless@npm:0.12.0" @@ -3231,6 +3434,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.5.73": + version: 1.5.122 + resolution: "electron-to-chromium@npm:1.5.122" + checksum: 10c0/e6bcb82e0c91687c9d93753393d438eb4d744c4d75e5d4e247c742ac45ca14611b3c5d5df138fd6671648a2868d5c7b429bef829fe2b3b990a8b7b1d9a8c01e6 + languageName: node + linkType: hard + "emittery@npm:^0.13.1": version: 0.13.1 resolution: "emittery@npm:0.13.1" @@ -3415,6 +3625,13 @@ __metadata: languageName: node linkType: hard +"escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 + languageName: node + linkType: hard + "escape-string-regexp@npm:^1.0.5": version: 1.0.5 resolution: "escape-string-regexp@npm:1.0.5" @@ -5128,11 +5345,13 @@ __metadata: version: 0.0.0-use.local resolution: "js-slang@workspace:." dependencies: + "@babel/core": "npm:^7.26.10" "@babel/parser": "npm:^7.19.4" "@babel/preset-env": "npm:^7.23.2" "@commander-js/extra-typings": "npm:^12.0.1" "@joeychenofficial/alt-ergo-modified": "npm:^2.4.0" "@ts-morph/bootstrap": "npm:^0.18.0" + "@types/babel__core": "npm:^7" "@types/estree": "npm:^1.0.5" "@types/jest": "npm:^29.0.0" "@types/lodash": "npm:^4.14.202" @@ -5334,6 +5553,15 @@ __metadata: languageName: node linkType: hard +"jsesc@npm:^3.0.2": + version: 3.1.0 + resolution: "jsesc@npm:3.1.0" + bin: + jsesc: bin/jsesc + checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1 + languageName: node + linkType: hard + "jsesc@npm:~0.5.0": version: 0.5.0 resolution: "jsesc@npm:0.5.0" @@ -5870,6 +6098,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.19": + version: 2.0.19 + resolution: "node-releases@npm:2.0.19" + checksum: 10c0/52a0dbd25ccf545892670d1551690fe0facb6a471e15f2cfa1b20142a5b255b3aa254af5f59d6ecb69c2bec7390bc643c43aa63b13bf5e64b6075952e716b1aa + languageName: node + linkType: hard + "nopt@npm:^8.0.0": version: 8.1.0 resolution: "nopt@npm:8.1.0" @@ -6170,6 +6405,13 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 + languageName: node + linkType: hard + "picomatch@npm:^2.0.4, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" @@ -7328,6 +7570,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.1.1": + version: 1.1.3 + resolution: "update-browserslist-db@npm:1.1.3" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10c0/682e8ecbf9de474a626f6462aa85927936cdd256fe584c6df2508b0df9f7362c44c957e9970df55dfe44d3623807d26316ea2c7d26b80bb76a16c56c37233c32 + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1"