Is there wildcard mechanism for listing sources in node-gyp - node-gyp

I'm writing binding.gyp file for my new node.js module. I have all my source files under src/ subdirectory. I would like to use all of them while building the module. Instead of modifying binding.gyp each time I add a new cpp file, I would like to list all cpp files through some wildcard mechanism. Does node-gyp support that? Something like following (which doesn't work
{
'targets' : [
{
'target_name' : 'mymod',
'sources' : 'src/*.cpp'
}
]
}
I looked at https://code.google.com/p/gyp/wiki/InputFormatReference , but didn't find anything readily useful.

Figured it out
{
'targets' : [
{
'target_name' : 'mymod',
'sources' : [ '<!#(ls -1 src/*.cpp)' ],
}
]
}
Check out this link
Update
The solution above is not portable across platforms. Here's a portable version:
{
'targets' : [
{
'target_name' : 'mymod',
'sources' : [ "<!#(node -p \"require('fs').readdirSync('./src').map(f=>'src/'+f).join(' ')\")" ],
}
]
}
Essentially it replaces the platform specific directory listing command (ls), by Javascript code that uses node's fs module to list the directory contents.

An even more portable version (that doesn't depend on node, but rather python):
"<!#(python -c \"import os; print '\n'.join(['%s' % x for x in os.listdir('.') if x[-3:] == '.cc' and 'test' not in x])\")"

To filter specific file extensions like cpp and to support also pre-compiled libraries .a files, I have slightly modified the accepted solution to be:
'sources': [
'jamspell.cpp',
"<!#(node -p \"require('fs').readdirSync('./src').filter(f=>f.endsWith('.cpp')).map(f=>'src/'+f).join(' ')\")",
"<!#(node -p \"require('fs').readdirSync('./src/jamspell').filter(f=>f.endsWith('.cpp')).map(f=>'src/jamspell/'+f).join(' ')\")"
],
'include_dirs': [
"<!#(node -p \"require('node-addon-api').include\")"
],
'libraries': [
"<!#(node -p \"require('fs').readdirSync('./lib/contrib').filter(f=>f.endsWith('.a')).map(f=>'lib/contrib/'+f).join(' ')\")"
],
'dependencies': [
"<!(node -p \"require('node-addon-api').gyp\")"
],

If anyone wants to include all sub files and folders within a certain folder (defined at end of line, here as "sources"):
{
"targets": [
{
"target_name": "addon",
"sources": [
"<!#(node -p \"var fs=require('fs'),path=require('path'),walk=function(r){let t,e=[],n=null;try{t=fs.readdirSync(r)}catch(r){n=r.toString()}if(n)return n;var a=0;return function n(){var i=t[a++];if(!i)return e;let u=path.resolve(r,i);i=r+'/'+i;let c=fs.statSync(u);if(c&&c.isDirectory()){let r=walk(i);return e=e.concat(r),n()}return e.push(i),n()}()};walk('./sources').join(' ');\")"
]
}
]
}
(based off, but not exactly: node.js fs.readdir recursive directory search)

Recursive script for windows, might work for linux/macos too.
"sources": [
"<!#(node sources.js)"
],
sources.js
const { resolve, relative } = require('path');
const { readdir } = require('fs').promises;
async function getFiles(dir) {
const dirents = await readdir(dir, { withFileTypes: true });
const files = await Promise.all(
dirents.map(dirent => {
const res = resolve(dir, dirent.name);
return dirent.isDirectory() ? getFiles(res) : res;
}),
);
return Array.prototype.concat(...files);
}
(async () => {
const files = (await getFiles(resolve(__dirname)))
.filter(
v =>
v.endsWith('.cpp') ||
v.endsWith('.h') ||
v.endsWith('.hpp') ||
v.endsWith('.cc') ||
v.endsWith('.c'),
)
.map(v => relative(__dirname, v))
.map(v => v.replace(/\\/g, '/')) // remove on mac/linux
.join(' ');
console.log(files);
return files;
})();

Related

React/Vite Build Error causing a Reducer to be wrongly exported

Hi I'm having a very weird error during build process of a React application with Vite.
When I run Vite as a dev server on local machine it works well, but during the build process there is an error on the resultant code.
The problem is actually with one reducer, which is not being exported as it should be, causing an error on the components that depends on that slice.
This is the generated source relating to the reducer causing issues:
var m = (0,
e.createSlice)({
name: "form",
initialState: {
list: {}
},
reducers: {
generateForm: function(q, j) {
var L = j.payload
, K = L.id
, U = L.fields
, W = L.values
, X = L.baseUrl
, ae = (0,
t.normalizeFields)(U);
q.list[K] = {
fields: ae,
values: W || null,
baseUrl: X || null
}
}
}
}
});
de.formSlice = m;
var E = m.actions,
h = E.generateForm;
de.generateForm = h;
var V = m.reducer;
return de.default = V,
de
While all other reducers work as intended, and build correctly, they look like this one for example:
var Wc = (0,
HE.createSlice)({
name: "datatable",
initialState: {
list: {}
},
reducers: {
clear: function(r, t) {
var n = t.payload.id;
delete r.list[n]
}
}
});
St.clear= Wc;
var Ml = Wc.actions
, GE = Ml.clear;
var sh = St.clear = GE
, XE = Wc.reducer
, ch = St.default = XE
, xt = {}
, Il = {};
Notice that the reducer that is failing is somehow returning both the entire slice object and the default export, while all other reducers simply assign the reducer to the default export.
The weird thing is that if I go with react-scripts all builds correctly, but I'd like to know why and If I'm missing a plugin or something.
My vite config looks like this:
export default defineConfig(({ mode }) => {
process.env = {
...process.env,
...process.env.development,
...loadEnv(mode, process.cwd())
};
return {
base: process.env.VITE_APP_BASENAME,
server: {
port: 3000
},
plugins: [
react({
babel: {
babelrc: true,
parserOpts: {
plugins: ["decorators-legacy"]
}
}
}),
EnvironmentPlugin("all", { prefix: "REACT_APP_" }),
istanbul({
include: ["src"],
exclude: ["node_modules", "test/", "cypress/"],
extension: [".js", ".jsx"]
})
],
build: {
rollupOptions: {
output: {
manualChunks: {
"react-venders": ["react", "react-dom"]
}
},
external: ["#vitjs/runtime"]
},
chunkSizeWarningLimit: 700
}
};
});
My .babelrc config is the following:
{
"presets": ["#babel/react"]
}
Also is pretty rare that in local serve mode (npm start) which runs Vite it does works well. It only fails during build process, and specifically on that Reducer (form).
Appreciate any help! Thanks

How to use custom style loader in Vite

We have a react project and using webpack for bundling but also we want to try vite too. Webpack bundle css files from style-loader.js too. In style-loader.js we have some rules which are related to components and components are added to node modules. My rule's aim is mainly importing css files from node_modules components. When we run our project with vite, Our custom scss files does not override css which came from components. Is there any solution for override or Is there any way to use a custom style loader in vite ?
Our custom style loader webpack-dev is;
module: {
rules: [
{
test: /\.js?$/,
exclude: /(node_modules|bower_components)/,
loader: './config/webpack/style-loader'
},
]}
Our style-loader.js file is;
const babylon = require('babylon');
const traverse = require('babel-traverse').default;
const fs = require('fs');
module.exports = function (source) {
var astResult = babylon.parse(source, {
sourceType: "module",
ranges: true,
plugins: [
"jsx",
"objectRestSpread",
"flow",
"typescript",
"decorators",
"doExpressions",
"classProperties",
"classPrivateProperties",
"classPrivateMethods",
"exportExtensions",
"asyncGenerators",
"functionBind",
"functionSent",
"dynamicImport",
"numericSeparator",
"optionalChaining",
"importMeta",
"bigInt",
"optionalCatchBinding"
]
});
let addedIndexCounter = 0;
let isViewDirty = false;
traverse(astResult, {
enter: function (path) {
let node = path.node;
if (node.type == 'ImportDeclaration' &&
node.source &&
node.source.type == 'StringLiteral' &&
node.source.value &&
node.source.value.indexOf('#packagename') >= 0 &&
node.source.value.indexOf('core') < 0 &&
node.source.value.indexOf('.css') < 0) {
if(fs.existsSync('./node_modules/' + node.source.value + '/styles.css')) {
let starting = node.end;
starting += addedIndexCounter;
let targettacCss = "; import '" + node.source.value + "/styles.css';"
addedIndexCounter += targettacCss.length;
source = source.substring(0, starting) + targettacCss + source.substring(starting);
isViewDirty = true;
}
}
}
});
/*if(isViewDirty){
let fileName = "view_" + (new Date()).toISOString().slice(0, 10)+"_" + Math.random().toString(35).substr(2,10);
fs.writeFileSync('./logs/views/' + fileName, source);
}*/
return source;
};
You can use plugins to achieve your feature, the following is my general idea.
// vite.config.js
import { defineConfig } from "vite";
import customerPlugin from "./plugin/customer-plugin";
export default defineConfig(() => {
return {
// ..
plugins: [customerPlugin()] // Put your plugin here
};
});
// ./plugin/customer-plugin.js
const customerPlugin = () => {
return {
name: "customer-transform",
transform(code, id) {
// id = "/some/path/xxx.js"
if (!id.endsWith(".js")) return; // Only transform js file.
let resultCode = "";
// Paste your transform logic here.
return resultCode;
}
};
};
export default customerPlugin;
reference: https://vitejs.dev/guide/api-plugin.html

vscode findFiles returns nothing but npm glob returns correct results

I'm writing and vscode extension in which I need a list of the test files inside workspace.
To find the test files I'm using the default testMatch from the jest.config.js which is:
[
'**/__tests__/**/*.[jt]s?(x)',
'**/?(*.)+(spec|test).[jt]s?(x)'
]
My problem is that vscode.workspace.findFiles returns empty array and I cannot set it up to get correct results, but using Glob package the output is correct.
protected async findTestFiles(
matchTestsGlobPatterns: string[]
): Promise<vscode.Uri[]> {
const testFilesUris: vscode.Uri[] = [];
const glob_testFilesUris: vscode.Uri[] = [];
const { name: workspaceName, workspaceFolders } = vscode.workspace;
if (workspaceName === undefined || workspaceFolders === undefined) {
throw new Error(`No active workspace${!workspaceFolders ? ' folders' : ''}.`);
}
for (let folderIdx = 0; folderIdx < workspaceFolders.length; folderIdx++) {
const folder = workspaceFolders[folderIdx];
// - by vscode.workspace.findFiles
for (let patternIdx = 0; patternIdx < matchTestsGlobPatterns.length; patternIdx++) {
const currentPattern = matchTestsGlobPatterns[patternIdx];
const pattern = new vscode.RelativePattern(
folder.uri.fsPath,
currentPattern
);
const files = await vscode.workspace.findFiles(
pattern,
'**/node_modules/**'
);
testFilesUris.push(...files);
}
console.log('by [vscode.workspace.findFiles]', testFilesUris.length);
// - by npm Glob
var glob = require('glob');
for (let patternIdx = 0; patternIdx < matchTestsGlobPatterns.length; patternIdx++) {
const currentPattern = matchTestsGlobPatterns[patternIdx];
const files: any[] = await new Promise((resolve, reject) => {
glob(
currentPattern,
{
absolute: true,
cwd: folder.uri.fsPath,
ignore: ['**/node_modules/**']
},
function (err: Error, files: any[]) {
if (err) {
return reject(err);
}
resolve(files);
}
);
});
glob_testFilesUris.push(...files);
}
console.log('by [npm Glob]', glob_testFilesUris.length);
}
// #todo: remove duplicates.
return testFilesUris;
}
The example console output of this function for some project is:
by [vscode.workspace.findFiles] 0
by [npm Glob] 45
Project structure:
rootFolder
src
__tests__
files.test.ts
...
utils
array.test.ts
...
So my question is how do I call vscode.workspace.findFiles to get correct results, or is there known problem with this function?
I have found some kind of answer to the question.
The problem is ?(x) in patterns. The vscode.workspace.findFiles does not work with this pattern as other packages do. If remove it from mentioned glob patterns they work except the .jsx | .tsx files are ommited.
After deep dive into vscode github's issues I have learned (here) that vscode.workspace.findFiles does not support extended patterns like ?(patterLike)

How to exclude folder from Typewriter code generation

I'm using the settings below to include project "Soft.Data" in my Typewriter code generation.
But how do I exclude a specific folder (e.g. "ViewModels") from the code generation?
Template(Settings settings)
{
settings.IncludeProject("Soft.Data");
settings.OutputFilenameFactory = file =>
{
return $"{file.Name.Replace("ViewModel", "GenViewModel").Replace(".cs", ".ts")}";
};
}
You can use a lambda filter in your template to exclude a namespace.
${
Template(Settings settings)
{
settings.IncludeProject("Soft.Data");
settings.OutputFilenameFactory = file =>
{
return $"{file.Name.Replace("ViewModel", "GenViewModel").Replace(".cs", ".ts")}";
};
}
}
$Classes(c => c.Namespace != "Soft.Data.ViewModels")[
...
]

Chrome Packaged App: Retrieving FileEntry in Dart from command line (LaunchData) parameter

Similarly to another post on this topic, I've been attempting to run my app from the command line with the file path of a local XML file so that my main.dart can parse this file in order to extract information relevant to program operation from it. I've been stumped as to how to appropriately access the FileEntry reference included in launchData -- the parameter for the onLaunched event.
Here's what I currently have:
manifest.json:
...
"permissions": [
"storage",
"fileSystem",
"*://*/*"
],
"file_handlers" : {
"any" : {
"types" : [ "*" ]
}
},
...
background.js:
chrome.app.runtime.onLaunched.addListener(function(launchData) {
chrome.app.window.create(
'htmlFile.html',
{...},
function(createdWindow) {
createdWindow.contentWindow.launchData = launchData;
});
});
At this point, I can't access launchData from main.dart because trying to do
FileEntry entry = (chrome.app.window.current().contentWindow.launchData as chrome.LaunchData).items.elementAt(0).entry;
to get the FileEntry results in an error for accessing launchData. I'm really confused about how I'm supposed to access the FileEntry that I want from my Dart code as a result.
I ended up with this as my solution:
manifest.json:
...
"file_handlers": {
"any": {
"extensions": [
"xml"
]
}
},
...
background.js:
chrome.app.runtime.onLaunched.addListener(function(launchData) {
chrome.app.window.create(
'htmlSource.html',
{
id: 'mainWindow',
state: "fullscreen"
},
function(createdWindow) {
if(launchData.items !== undefined) {
launchData.items[0].entry.file(
function(result) {
var reader = new FileReader();
var XML;
reader.onloadend = function(){
XML = reader.result;
chrome.storage.local.set({'XML': XML});
};
reader.readAsText(result);
},
function(){
console.log("Error reading XML file");
}
);
} else {
console.log("No file was detected.");
}
});
});
The dart code to retrieve the XML was simply:
String text = (await chrome.storage.local.get('XML'))['XML'];

Resources