1'use strict'; 2 3// doc/api/addons.md has a bunch of code. Extract it for verification 4// that the C++ code compiles and the js code runs. 5// Add .gyp files which will be used to compile the C++ code. 6// Modify the require paths in the js code to pull from the build tree. 7// Triggered from the build-addons target in the Makefile and vcbuild.bat. 8 9const { mkdir, writeFile } = require('fs'); 10const { resolve } = require('path'); 11const vfile = require('to-vfile'); 12const unified = require('unified'); 13const remarkParse = require('remark-parse'); 14 15const rootDir = resolve(__dirname, '..', '..'); 16const doc = resolve(rootDir, 'doc', 'api', 'addons.md'); 17const verifyDir = resolve(rootDir, 'test', 'addons'); 18 19const file = vfile.readSync(doc, 'utf8'); 20const tree = unified().use(remarkParse).parse(file); 21const addons = {}; 22let id = 0; 23let currentHeader; 24 25const validNames = /^\/\/\s+(.*\.(?:cc|h|js))[\r\n]/; 26tree.children.forEach((node) => { 27 if (node.type === 'heading') { 28 currentHeader = file.contents.slice( 29 node.children[0].position.start.offset, 30 node.position.end.offset); 31 addons[currentHeader] = { files: {} }; 32 } else if (node.type === 'code') { 33 const match = node.value.match(validNames); 34 if (match !== null) { 35 addons[currentHeader].files[match[1]] = node.value; 36 } 37 } 38}); 39 40Object.keys(addons).forEach((header) => { 41 verifyFiles(addons[header].files, header); 42}); 43 44function verifyFiles(files, blockName) { 45 const fileNames = Object.keys(files); 46 47 // Must have a .cc and a .js to be a valid test. 48 if (!fileNames.some((name) => name.endsWith('.cc')) || 49 !fileNames.some((name) => name.endsWith('.js'))) { 50 return; 51 } 52 53 blockName = blockName.toLowerCase().replace(/\s/g, '_').replace(/\W/g, ''); 54 const dir = resolve( 55 verifyDir, 56 `${String(++id).padStart(2, '0')}_${blockName}` 57 ); 58 59 files = fileNames.map((name) => { 60 if (name === 'test.js') { 61 files[name] = `'use strict'; 62const common = require('../../common'); 63${files[name].replace( 64 "'./build/Release/addon'", 65 // eslint-disable-next-line no-template-curly-in-string 66 '`./build/${common.buildType}/addon`')} 67`; 68 } 69 return { 70 path: resolve(dir, name), 71 name: name, 72 content: files[name] 73 }; 74 }); 75 76 files.push({ 77 path: resolve(dir, 'binding.gyp'), 78 content: JSON.stringify({ 79 targets: [ 80 { 81 target_name: 'addon', 82 sources: files.map(({ name }) => name), 83 includes: ['../common.gypi'], 84 }, 85 ] 86 }) 87 }); 88 89 mkdir(dir, () => { 90 // Ignore errors. 91 92 files.forEach(({ path, content }) => { 93 writeFile(path, content, (err) => { 94 if (err) 95 throw err; 96 97 console.log(`Wrote ${path}`); 98 }); 99 }); 100 }); 101} 102