fix(dart): patch NAN→NAPI bindings and remove invalid nullable_type query

tree-sitter-dart@1.0.0 ships with NAN-style native bindings that are
incompatible with tree-sitter@0.21.x (NAPI). This causes the Dart parser
to fail to load, silently disabling all Dart symbol extraction.

Changes:
1. build-tree-sitter-dart.cjs: Auto-patch binding.cc, binding.gyp, and
   index.js to NAPI style before running node-gyp rebuild. The patch
   mirrors the pattern used by tree-sitter-go and other bundled parsers.
2. tree-sitter-queries.ts: Remove the nullable_type query pattern.
   tree-sitter-dart@1.0.0 grammar has no nullable_type node — nullable
   fields (e.g. String? name) are parsed as (type_identifier) + "?"
   anonymous token. The existing typed-field query already captures them.

Tested on a real Flutter project (~57k Dart symbols extracted).

Fixes #584
This commit is contained in:
David 2026-05-07 10:40:36 +08:00
parent 68e4a5aece
commit 1e734a3348
2 changed files with 88 additions and 7 deletions

View file

@ -26,6 +26,94 @@ try {
process.exit(0);
}
// ── Patch NAN → NAPI bindings ──────────────────────────────────────────
// tree-sitter-dart@1.0.0 ships old NAN-style bindings that are
// incompatible with the tree-sitter@0.21.x runtime bundled by GitNexus.
// Rewrite binding.cc, binding.gyp, and index.js to NAPI style (same
// pattern used by tree-sitter-go, tree-sitter-python, etc.).
const bindingCc = path.join(dartDir, 'bindings', 'node', 'binding.cc');
const indexJs = path.join(dartDir, 'bindings', 'node', 'index.js');
if (fs.existsSync(bindingCc)) {
const currentCc = fs.readFileSync(bindingCc, 'utf8');
if (currentCc.includes('Nan::') || !currentCc.includes('Napi::')) {
console.log('[tree-sitter-dart] Patching binding.cc (NAN → NAPI)...');
fs.writeFileSync(
bindingCc,
[
'#include <napi.h>',
'',
'typedef struct TSLanguage TSLanguage;',
'',
'extern "C" TSLanguage *tree_sitter_dart();',
'',
'// "tree-sitter", "language" is a convention that lets the',
'// temporary `node-tree-sitter` binding find the language.',
'Napi::Object Init(Napi::Env env, Napi::Object exports) {',
' exports["name"] = Napi::String::New(env, "dart");',
' auto language = Napi::External<TSLanguage>::New(env, tree_sitter_dart());',
' language.TypeTag(&language);',
' exports["language"] = language;',
' return exports;',
'}',
'',
'NODE_API_MODULE(tree_sitter_dart_binding, Init)',
'',
].join('\n'),
);
}
}
if (fs.existsSync(bindingGyp)) {
const currentGyp = fs.readFileSync(bindingGyp, 'utf8');
if (currentGyp.includes('nan') || !currentGyp.includes('node-addon-api')) {
console.log('[tree-sitter-dart] Patching binding.gyp (NAN → NAPI)...');
fs.writeFileSync(
bindingGyp,
JSON.stringify(
{
targets: [
{
target_name: 'tree_sitter_dart_binding',
dependencies: ['<!(node -p "require(\'node-addon-api\').targets"):node_addon_api'],
include_dirs: ['src'],
sources: ['bindings/node/binding.cc', 'src/parser.c', 'src/scanner.c'],
cflags_c: ['-std=c11'],
cflags_cc: ['-std=c++17'],
defines: ['NAPI_VERSION=8', 'NODE_ADDON_API_DISABLE_DEPRECATED'],
xcode_settings: {
OTHER_CFLAGS: ['-std=c11'],
OTHER_CPLUSPLUSFLAGS: ['-std=c++17'],
},
},
],
},
null,
2,
) + '\n',
);
}
}
if (fs.existsSync(indexJs)) {
const currentIdx = fs.readFileSync(indexJs, 'utf8');
if (!currentIdx.includes('node-gyp-build')) {
console.log('[tree-sitter-dart] Patching index.js (node-gyp-build loader)...');
fs.writeFileSync(
indexJs,
[
'try {',
" module.exports = require('node-gyp-build')(__dirname + '/../..');",
'} catch (e) {',
" throw new Error('tree-sitter-dart native binding not found: ' + e.message);",
'}',
'',
].join('\n'),
);
}
}
// ── Build ──────────────────────────────────────────────────────────────
console.log('[tree-sitter-dart] Building native binding...');
execSync('npx node-gyp rebuild', {
cwd: dartDir,

View file

@ -1330,13 +1330,6 @@ export const DART_QUERIES = `
(initialized_identifier
(identifier) @name))) @definition.property
; ── Nullable field declarations (String? name) ──────────────────────────────
(declaration
(nullable_type)
(initialized_identifier_list
(initialized_identifier
(identifier) @name))) @definition.property
; ── Getters ──────────────────────────────────────────────────────────────────
(method_signature
(getter_signature