feat(flight-finder): implement milestone M1 - domain model and skill contract

This commit is contained in:
2026-03-30 16:45:40 -05:00
parent 57f6b132b2
commit 9c7103770a
1237 changed files with 901934 additions and 0 deletions

View File

@@ -0,0 +1,218 @@
import { parseFiles } from "@ast-grep/napi";
import { chalk, fs, path } from "zx";
import { errors } from "./errors.js";
import { root } from "./utils.js";
/**
* @typedef {import("@ast-grep/napi").SgNode} SgNode
*/
/**
* Prepend text to a node
* @param {SgNode} node
* @param {string} text
* @returns {import("@ast-grep/napi").Edit}
*/
function prepend(node, text) {
const index = node.range().start.index;
return {
startPos: index,
endPos: index,
insertedText: text,
};
}
export function ast_grep() {
const task_queue = [];
const task = parseFiles([root("esm")], (err, tree) => {
const filename = path.basename(tree.filename(), ".js");
if (filename === "index") {
return;
}
const root_node = tree.root();
const edits = [];
edits.push(prepend(root_node, `"use strict";\n\n`));
// We have forked _ts_generator from tslib
if (filename.startsWith("_ts") && filename !== "_ts_generator") {
const match = root_node.find(`export { $NAME as _ } from "tslib"`);
if (match) {
const name = match.getMatch("NAME").text();
edits.push(
match.replace(`exports._ = require("tslib").${name};`),
);
task_queue.push(
fs.writeFile(root("cjs", `${filename}.cjs`), root_node.commitEdits(edits), {
encoding: "utf-8",
}),
);
} else {
report_noexport(tree.filename());
}
return;
}
// rewrite export named function
const match = root_node.find({
rule: {
kind: "export_statement",
pattern: "export { $FUNC as _ }",
},
});
if (match) {
const func = match.getMatch("FUNC");
const func_name = func.text();
if (func_name !== filename) {
report_export_mismatch(tree.filename(), match);
}
edits.push(
match.replace(`exports._ = ${func_name};`),
);
// since we match the { export x as _ } pattern,
// we need to find the assignment expression from the root
root_node
.findAll({
rule: {
pattern: func_name,
kind: "identifier",
inside: { kind: "assignment_expression", field: "left" },
},
})
.forEach((node) => {
edits.push(
prepend(node, `exports._ = `),
);
});
} else {
report_noexport(tree.filename());
}
// rewrite import
root_node
.findAll({ rule: { pattern: `import { _ as $BINDING } from "$SOURCE"` } })
.forEach((match) => {
const import_binding = match.getMatch("BINDING").text();
const import_source = match.getMatch("SOURCE").text();
const import_basename = path.basename(import_source, ".js");
if (import_binding !== import_basename) {
report_import_mismatch(tree.filename(), match);
}
edits.push(
match.replace(`var ${import_binding} = require("./${import_binding}.cjs");`),
);
root_node
.findAll({
rule: {
pattern: import_binding,
kind: "identifier",
inside: {
not: {
kind: "import_specifier",
},
},
},
})
.forEach((node) => {
edits.push(
node.replace(`${node.text()}._`),
);
});
});
task_queue.push(
fs.writeFile(root("cjs", `${filename}.cjs`), root_node.commitEdits(edits), {
encoding: "utf-8",
}),
);
});
task_queue.push(task);
return task_queue;
}
/**
* @param {string} filename
* @param {SgNode} match
*/
function report_export_mismatch(filename, match) {
const func = match.getMatch("FUNC");
const func_range = func.range();
const text = match.text().split("\n");
const offset = func_range.start.line - match.range().start.line;
text.splice(
offset + 1,
text.length,
chalk.red(
[
" ".repeat(func_range.start.column),
"^".repeat(func_range.end.column - func_range.start.column),
]
.join(""),
),
);
errors.push(
[
`${chalk.bold.red("error")}: mismatch exported function name.`,
"",
`${chalk.blue("-->")} ${filename}:${func_range.start.line + 1}:${func_range.start.column + 1}`,
"",
...text,
"",
`${chalk.bold("note:")} The exported name should be the same as the filename.`,
"",
]
.join("\n"),
);
}
/**
* @param {string} filename
* @param {SgNode} match
*/
function report_import_mismatch(filename, match) {
const binding_range = match.getMatch("BINDING").range();
const source_range = match.getMatch("SOURCE").range();
errors.push(
[
`${chalk.bold.red("error")}: mismatch imported binding name.`,
"",
`${chalk.blue("-->")} ${filename}:${match.range().start.line + 1}`,
"",
match.text(),
[
" ".repeat(binding_range.start.column),
chalk.red("^".repeat(binding_range.end.column - binding_range.start.column)),
" ".repeat(source_range.start.column - binding_range.end.column),
chalk.blue("-".repeat(source_range.end.column - source_range.start.column)),
]
.join(""),
`${chalk.bold("note:")} The imported binding name should be the same as the import source basename.`,
"",
]
.join("\n"),
);
}
/**
* @param {string} filename
*/
function report_noexport(filename) {
errors.push(
[`${chalk.bold.red("error")}: exported name not found`, `${chalk.blue("-->")} ${filename}`].join("\n"),
);
}

View File

@@ -0,0 +1,133 @@
#!/usr/bin/env zx
import { $, fs, glob } from "zx";
import { ast_grep } from "./ast_grep.js";
import { errors } from "./errors.js";
import { root } from "./utils.js";
// clear generated content
await Promise.all([
fs.remove(root("cjs")),
fs.remove(root("_")),
fs.remove(root("src")),
]);
let modules = await glob("*.js", { cwd: root("esm") });
const task_queue = [];
const NO_MODIFY = [
"/* This file is automatically generated and should not be manually edited. */",
"/* To modify this file, please run the `npm run build` command instead. */",
];
// generate index.js
const indexESM = [...NO_MODIFY, ""];
const indexCJS = [`"use strict";`, "", ...NO_MODIFY, ""];
const cjs_export_list = [];
const cjs_module_lexer = [];
const main_package_json = fs.readJSONSync(root("package.json"));
main_package_json.exports = {
"./package.json": "./package.json",
"./esm/*": "./esm/*",
"./cjs/*": "./cjs/*",
"./src/*": "./src/*",
".": {
"module-sync": "./esm/index.js",
webpack: "./esm/index.js",
import: "./esm/index.js",
default: "./cjs/index.cjs",
},
"./_": {
"module-sync": "./esm/index.js",
webpack: "./esm/index.js",
import: "./esm/index.js",
default: "./cjs/index.cjs",
},
};
modules.forEach((p) => {
const importBinding = p.slice(0, -3);
main_package_json.exports[`./_/${importBinding}`] = {
"module-sync": `./esm/${importBinding}.js`,
webpack: `./esm/${importBinding}.js`,
import: `./esm/${importBinding}.js`,
default: `./cjs/${importBinding}.cjs`,
};
const alias_package = {
main: `../../cjs/${importBinding}.cjs`,
module: `../../esm/${importBinding}.js`,
};
task_queue.push(
fs.outputJSON(root("_", importBinding, "package.json"), alias_package, {
encoding: "utf-8",
spaces: 4,
}),
);
if (importBinding === "index") {
return;
}
task_queue.push(
fs.outputFile(root("src", `${importBinding}.mjs`), re_export_esm(importBinding), {
encoding: "utf-8",
}),
);
indexESM.push(`export { _ as ${importBinding} } from "./${importBinding}.js";`);
cjs_module_lexer.push(`${importBinding}: null,`);
cjs_export_list.push(`get ${importBinding}() {
return require("./${importBinding}.cjs")._;
},`);
});
indexCJS.push(
`0 && (module.exports = {`,
"/* @Annotate_start: the CommonJS named exports for ESM import in node */",
...cjs_module_lexer,
"/* @Annotate_end */",
`});`,
`module.exports = {`,
...cjs_export_list,
`};`,
);
task_queue.push(
fs.outputJSON(root("package.json"), main_package_json, { spaces: 4 }),
fs.outputFile(root("esm", "index.js"), indexESM.join("\n") + "\n", {
encoding: "utf-8",
}),
fs.outputFile(root("cjs", "index.cjs"), indexCJS.join("\n") + "\n", {
encoding: "utf-8",
}),
fs.outputFile(root("src", "index.mjs"), `export * from "../esm/index.js"`, {
encoding: "utf-8",
}),
);
task_queue.push(...ast_grep());
await Promise.all(task_queue);
if (errors.length > 0) {
errors.forEach((e) => {
console.error(e);
});
process.exitCode = 1;
} else {
$.cwd = root(".");
await $`dprint fmt`;
await $`dprint fmt "scripts/*.js" -c scripts/.dprint.json`;
}
function re_export_esm(importBinding) {
return `export { _ as default } from "../esm/${importBinding}.js"`;
}

View File

@@ -0,0 +1 @@
export const errors = [];

View File

@@ -0,0 +1,3 @@
export function root(...p) {
return path.resolve(__dirname, "..", ...p);
}