@ncukondo/search-hub 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_commonjsHelpers.js +30 -0
- package/dist/_virtual/_commonjsHelpers.js.map +1 -0
- package/dist/_virtual/aliases.js +5 -0
- package/dist/_virtual/aliases.js.map +1 -0
- package/dist/_virtual/attributes.js +5 -0
- package/dist/_virtual/attributes.js.map +1 -0
- package/dist/_virtual/back.js +5 -0
- package/dist/_virtual/back.js.map +1 -0
- package/dist/_virtual/comment.js +5 -0
- package/dist/_virtual/comment.js.map +1 -0
- package/dist/_virtual/compile.js +5 -0
- package/dist/_virtual/compile.js.map +1 -0
- package/dist/_virtual/compile2.js +5 -0
- package/dist/_virtual/compile2.js.map +1 -0
- package/dist/_virtual/decode-data-html.js +5 -0
- package/dist/_virtual/decode-data-html.js.map +1 -0
- package/dist/_virtual/decode-data-xml.js +5 -0
- package/dist/_virtual/decode-data-xml.js.map +1 -0
- package/dist/_virtual/decode.js +5 -0
- package/dist/_virtual/decode.js.map +1 -0
- package/dist/_virtual/decode_codepoint.js +5 -0
- package/dist/_virtual/decode_codepoint.js.map +1 -0
- package/dist/_virtual/encode-html.js +5 -0
- package/dist/_virtual/encode-html.js.map +1 -0
- package/dist/_virtual/encode.js +5 -0
- package/dist/_virtual/encode.js.map +1 -0
- package/dist/_virtual/escape.js +5 -0
- package/dist/_virtual/escape.js.map +1 -0
- package/dist/_virtual/feeds.js +5 -0
- package/dist/_virtual/feeds.js.map +1 -0
- package/dist/_virtual/filters.js +5 -0
- package/dist/_virtual/filters.js.map +1 -0
- package/dist/_virtual/foreignNames.js +5 -0
- package/dist/_virtual/foreignNames.js.map +1 -0
- package/dist/_virtual/general.js +5 -0
- package/dist/_virtual/general.js.map +1 -0
- package/dist/_virtual/he.js +5 -0
- package/dist/_virtual/he.js.map +1 -0
- package/dist/_virtual/helpers.js +5 -0
- package/dist/_virtual/helpers.js.map +1 -0
- package/dist/_virtual/html.js +5 -0
- package/dist/_virtual/html.js.map +1 -0
- package/dist/_virtual/index.js +6 -0
- package/dist/_virtual/index.js.map +1 -0
- package/dist/_virtual/index10.js +5 -0
- package/dist/_virtual/index10.js.map +1 -0
- package/dist/_virtual/index11.js +5 -0
- package/dist/_virtual/index11.js.map +1 -0
- package/dist/_virtual/index2.js +5 -0
- package/dist/_virtual/index2.js.map +1 -0
- package/dist/_virtual/index3.js +5 -0
- package/dist/_virtual/index3.js.map +1 -0
- package/dist/_virtual/index4.js +5 -0
- package/dist/_virtual/index4.js.map +1 -0
- package/dist/_virtual/index5.js +7 -0
- package/dist/_virtual/index5.js.map +1 -0
- package/dist/_virtual/index6.js +5 -0
- package/dist/_virtual/index6.js.map +1 -0
- package/dist/_virtual/index7.js +5 -0
- package/dist/_virtual/index7.js.map +1 -0
- package/dist/_virtual/index8.js +5 -0
- package/dist/_virtual/index8.js.map +1 -0
- package/dist/_virtual/index9.js +5 -0
- package/dist/_virtual/index9.js.map +1 -0
- package/dist/_virtual/legacy.js +5 -0
- package/dist/_virtual/legacy.js.map +1 -0
- package/dist/_virtual/manipulation.js +5 -0
- package/dist/_virtual/manipulation.js.map +1 -0
- package/dist/_virtual/matcher.js +5 -0
- package/dist/_virtual/matcher.js.map +1 -0
- package/dist/_virtual/node.js +5 -0
- package/dist/_virtual/node.js.map +1 -0
- package/dist/_virtual/node2.js +5 -0
- package/dist/_virtual/node2.js.map +1 -0
- package/dist/_virtual/parse.js +5 -0
- package/dist/_virtual/parse.js.map +1 -0
- package/dist/_virtual/parse2.js +5 -0
- package/dist/_virtual/parse2.js.map +1 -0
- package/dist/_virtual/pseudos.js +5 -0
- package/dist/_virtual/pseudos.js.map +1 -0
- package/dist/_virtual/querying.js +5 -0
- package/dist/_virtual/querying.js.map +1 -0
- package/dist/_virtual/sort.js +5 -0
- package/dist/_virtual/sort.js.map +1 -0
- package/dist/_virtual/stringify.js +5 -0
- package/dist/_virtual/stringify.js.map +1 -0
- package/dist/_virtual/subselects.js +5 -0
- package/dist/_virtual/subselects.js.map +1 -0
- package/dist/_virtual/text.js +5 -0
- package/dist/_virtual/text.js.map +1 -0
- package/dist/_virtual/traversal.js +5 -0
- package/dist/_virtual/traversal.js.map +1 -0
- package/dist/_virtual/type.js +5 -0
- package/dist/_virtual/type.js.map +1 -0
- package/dist/_virtual/valid.js +5 -0
- package/dist/_virtual/valid.js.map +1 -0
- package/dist/_virtual/void-tag.js +5 -0
- package/dist/_virtual/void-tag.js.map +1 -0
- package/dist/cli/commands/diff.js +2 -2
- package/dist/cli/commands/diff.js.map +1 -1
- package/dist/cli/commands/fulltext/attach.js +1 -1
- package/dist/cli/commands/fulltext/attach.js.map +1 -1
- package/dist/cli/commands/fulltext/check.d.ts +1 -2
- package/dist/cli/commands/fulltext/check.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/check.js +4 -2
- package/dist/cli/commands/fulltext/check.js.map +1 -1
- package/dist/cli/commands/fulltext/convert.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/convert.js +8 -8
- package/dist/cli/commands/fulltext/convert.js.map +1 -1
- package/dist/cli/commands/fulltext/fetch.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/fetch.js +10 -6
- package/dist/cli/commands/fulltext/fetch.js.map +1 -1
- package/dist/cli/commands/fulltext/index.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/index.js +2 -0
- package/dist/cli/commands/fulltext/index.js.map +1 -1
- package/dist/cli/commands/fulltext/init.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/init.js +6 -5
- package/dist/cli/commands/fulltext/init.js.map +1 -1
- package/dist/cli/commands/fulltext/pending.d.ts +1 -1
- package/dist/cli/commands/fulltext/pending.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/pending.js +4 -2
- package/dist/cli/commands/fulltext/pending.js.map +1 -1
- package/dist/cli/commands/fulltext/status.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/status.js +4 -2
- package/dist/cli/commands/fulltext/status.js.map +1 -1
- package/dist/cli/commands/fulltext/sync.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/sync.js +6 -2
- package/dist/cli/commands/fulltext/sync.js.map +1 -1
- package/dist/cli/commands/query/init.d.ts +5 -0
- package/dist/cli/commands/query/init.d.ts.map +1 -1
- package/dist/cli/commands/query/init.js +9 -1
- package/dist/cli/commands/query/init.js.map +1 -1
- package/dist/cli/commands/query/translate.d.ts.map +1 -1
- package/dist/cli/commands/query/translate.js +5 -0
- package/dist/cli/commands/query/translate.js.map +1 -1
- package/dist/cli/commands/query/validate.d.ts +22 -1
- package/dist/cli/commands/query/validate.d.ts.map +1 -1
- package/dist/cli/commands/query/validate.js +65 -22
- package/dist/cli/commands/query/validate.js.map +1 -1
- package/dist/cli/commands/review/extract.d.ts.map +1 -1
- package/dist/cli/commands/review/extract.js +1 -2
- package/dist/cli/commands/review/extract.js.map +1 -1
- package/dist/cli/commands/review/finalize.d.ts.map +1 -1
- package/dist/cli/commands/review/finalize.js +1 -2
- package/dist/cli/commands/review/finalize.js.map +1 -1
- package/dist/cli/commands/review/init.d.ts.map +1 -1
- package/dist/cli/commands/review/init.js +2 -5
- package/dist/cli/commands/review/init.js.map +1 -1
- package/dist/cli/commands/review/merge.d.ts.map +1 -1
- package/dist/cli/commands/review/merge.js +1 -2
- package/dist/cli/commands/review/merge.js.map +1 -1
- package/dist/cli/commands/review/types.d.ts +1 -1
- package/dist/cli/commands/review/types.d.ts.map +1 -1
- package/dist/cli/commands/review/types.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +81 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/suggestions/index.d.ts.map +1 -1
- package/dist/cli/suggestions/index.js +10 -0
- package/dist/cli/suggestions/index.js.map +1 -1
- package/dist/cli/suggestions/rules.d.ts.map +1 -1
- package/dist/cli/suggestions/rules.js +21 -8
- package/dist/cli/suggestions/rules.js.map +1 -1
- package/dist/cli/suggestions/types.d.ts +11 -0
- package/dist/cli/suggestions/types.d.ts.map +1 -1
- package/dist/config/schema.d.ts +2 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +6 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/{fulltext → integration}/attach-shared.d.ts +2 -2
- package/dist/integration/attach-shared.d.ts.map +1 -0
- package/dist/integration/attach-shared.js.map +1 -0
- package/dist/integration/fulltext-attach.js +1 -1
- package/dist/integration/fulltext-attach.js.map +1 -1
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/citation-key.js +1 -1
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/citation-key.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/arxiv-html-parser.js +434 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/arxiv-html-parser.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/index.js +93 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/index.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/jats-parser.js +1060 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/jats-parser.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/convert/markdown-writer.js +146 -117
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/markdown-writer.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/arxiv.js +8 -1
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/arxiv.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/core.js +6 -3
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/core.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/index.js +139 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/index.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/ncbi-id-converter.js +46 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/ncbi-id-converter.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/pmc.js +8 -4
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/pmc.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/unpaywall.js +43 -9
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/unpaywall.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/arxiv-html.js +48 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/arxiv-html.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/downloader.js +64 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/downloader.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/orchestrator.js +236 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/orchestrator.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/download/pmc-xml.js +2 -1
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/pmc-xml.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/meta.js +15 -10
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/meta.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/paths.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/readme.js +8 -4
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/readme.js.map +1 -0
- package/dist/node_modules/boolbase/index.js +19 -0
- package/dist/node_modules/boolbase/index.js.map +1 -0
- package/dist/node_modules/css-select/lib/attributes.js +203 -0
- package/dist/node_modules/css-select/lib/attributes.js.map +1 -0
- package/dist/node_modules/css-select/lib/compile.js +141 -0
- package/dist/node_modules/css-select/lib/compile.js.map +1 -0
- package/dist/node_modules/css-select/lib/general.js +154 -0
- package/dist/node_modules/css-select/lib/general.js.map +1 -0
- package/dist/node_modules/css-select/lib/index.js +128 -0
- package/dist/node_modules/css-select/lib/index.js.map +1 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/aliases.js +40 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/aliases.js.map +1 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/filters.js +163 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/filters.js.map +1 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/index.js +71 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/index.js.map +1 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/pseudos.js +93 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/pseudos.js.map +1 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/subselects.js +111 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/subselects.js.map +1 -0
- package/dist/node_modules/css-select/lib/sort.js +78 -0
- package/dist/node_modules/css-select/lib/sort.js.map +1 -0
- package/dist/node_modules/css-what/lib/es/index.js +12 -0
- package/dist/node_modules/css-what/lib/es/index.js.map +1 -0
- package/dist/node_modules/css-what/lib/es/parse.js +349 -0
- package/dist/node_modules/css-what/lib/es/parse.js.map +1 -0
- package/dist/node_modules/css-what/lib/es/stringify.js +102 -0
- package/dist/node_modules/css-what/lib/es/stringify.js.map +1 -0
- package/dist/node_modules/css-what/lib/es/types.js +37 -0
- package/dist/node_modules/css-what/lib/es/types.js.map +1 -0
- package/dist/node_modules/dom-serializer/lib/foreignNames.js +117 -0
- package/dist/node_modules/dom-serializer/lib/foreignNames.js.map +1 -0
- package/dist/node_modules/dom-serializer/lib/index.js +207 -0
- package/dist/node_modules/dom-serializer/lib/index.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode.js +368 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode_codepoint.js +70 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode_codepoint.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/encode.js +61 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/encode.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/escape.js +79 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/escape.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-html.js +18 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-html.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-xml.js +18 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-xml.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/encode-html.js +19 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/encode-html.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/index.js +139 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/index.js.map +1 -0
- package/dist/node_modules/domelementtype/lib/index.js +40 -0
- package/dist/node_modules/domelementtype/lib/index.js.map +1 -0
- package/dist/node_modules/domhandler/lib/index.js +167 -0
- package/dist/node_modules/domhandler/lib/index.js.map +1 -0
- package/dist/node_modules/domhandler/lib/node.js +439 -0
- package/dist/node_modules/domhandler/lib/node.js.map +1 -0
- package/dist/node_modules/domutils/lib/feeds.js +146 -0
- package/dist/node_modules/domutils/lib/feeds.js.map +1 -0
- package/dist/node_modules/domutils/lib/helpers.js +97 -0
- package/dist/node_modules/domutils/lib/helpers.js.map +1 -0
- package/dist/node_modules/domutils/lib/index.js +65 -0
- package/dist/node_modules/domutils/lib/index.js.map +1 -0
- package/dist/node_modules/domutils/lib/legacy.js +124 -0
- package/dist/node_modules/domutils/lib/legacy.js.map +1 -0
- package/dist/node_modules/domutils/lib/manipulation.js +107 -0
- package/dist/node_modules/domutils/lib/manipulation.js.map +1 -0
- package/dist/node_modules/domutils/lib/querying.js +102 -0
- package/dist/node_modules/domutils/lib/querying.js.map +1 -0
- package/dist/node_modules/domutils/lib/stringify.js +65 -0
- package/dist/node_modules/domutils/lib/stringify.js.map +1 -0
- package/dist/node_modules/domutils/lib/traversal.js +69 -0
- package/dist/node_modules/domutils/lib/traversal.js.map +1 -0
- package/dist/node_modules/he/he.js +256 -0
- package/dist/node_modules/he/he.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/back.js +16 -0
- package/dist/node_modules/node-html-parser/dist/back.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/index.js +48 -0
- package/dist/node_modules/node-html-parser/dist/index.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/matcher.js +112 -0
- package/dist/node_modules/node-html-parser/dist/matcher.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/nodes/comment.js +41 -0
- package/dist/node_modules/node-html-parser/dist/nodes/comment.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/nodes/html.js +1048 -0
- package/dist/node_modules/node-html-parser/dist/nodes/html.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/nodes/node.js +49 -0
- package/dist/node_modules/node-html-parser/dist/nodes/node.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/nodes/text.js +106 -0
- package/dist/node_modules/node-html-parser/dist/nodes/text.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/nodes/type.js +19 -0
- package/dist/node_modules/node-html-parser/dist/nodes/type.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/parse.js +20 -0
- package/dist/node_modules/node-html-parser/dist/parse.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/valid.js +19 -0
- package/dist/node_modules/node-html-parser/dist/valid.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/void-tag.js +36 -0
- package/dist/node_modules/node-html-parser/dist/void-tag.js.map +1 -0
- package/dist/node_modules/nth-check/lib/compile.js +76 -0
- package/dist/node_modules/nth-check/lib/compile.js.map +1 -0
- package/dist/node_modules/nth-check/lib/index.js +36 -0
- package/dist/node_modules/nth-check/lib/index.js.map +1 -0
- package/dist/node_modules/nth-check/lib/parse.js +69 -0
- package/dist/node_modules/nth-check/lib/parse.js.map +1 -0
- package/dist/providers/arxiv/translator.d.ts.map +1 -1
- package/dist/providers/arxiv/translator.js +5 -2
- package/dist/providers/arxiv/translator.js.map +1 -1
- package/dist/providers/base/types.d.ts +2 -0
- package/dist/providers/base/types.d.ts.map +1 -1
- package/dist/providers/base/types.js.map +1 -1
- package/dist/providers/base/warnings.d.ts +14 -0
- package/dist/providers/base/warnings.d.ts.map +1 -0
- package/dist/providers/base/warnings.js +33 -0
- package/dist/providers/base/warnings.js.map +1 -0
- package/dist/providers/eric/translator.d.ts.map +1 -1
- package/dist/providers/eric/translator.js +5 -2
- package/dist/providers/eric/translator.js.map +1 -1
- package/dist/providers/pubmed/translator.d.ts.map +1 -1
- package/dist/providers/pubmed/translator.js +5 -2
- package/dist/providers/pubmed/translator.js.map +1 -1
- package/dist/providers/scopus/translator.d.ts.map +1 -1
- package/dist/providers/scopus/translator.js +22 -5
- package/dist/providers/scopus/translator.js.map +1 -1
- package/dist/query/__test-helpers__/mock-mesh-client.d.ts +12 -0
- package/dist/query/__test-helpers__/mock-mesh-client.d.ts.map +1 -0
- package/dist/query/index.d.ts +4 -0
- package/dist/query/index.d.ts.map +1 -1
- package/dist/query/json-schema.d.ts +3 -0
- package/dist/query/json-schema.d.ts.map +1 -0
- package/dist/query/json-schema.js +48 -0
- package/dist/query/json-schema.js.map +1 -0
- package/dist/query/mesh-lookup.d.ts +47 -0
- package/dist/query/mesh-lookup.d.ts.map +1 -0
- package/dist/query/mesh-lookup.js +151 -0
- package/dist/query/mesh-lookup.js.map +1 -0
- package/dist/query/parser.js +1 -1
- package/dist/query/parser.js.map +1 -1
- package/dist/query/types.d.ts +2 -2
- package/dist/query/types.d.ts.map +1 -1
- package/dist/query/validator.d.ts +5 -5
- package/dist/query/validator.d.ts.map +1 -1
- package/dist/query/validator.js +5 -2
- package/dist/query/validator.js.map +1 -1
- package/dist/query/vocab-cache.d.ts +15 -0
- package/dist/query/vocab-cache.d.ts.map +1 -0
- package/dist/query/vocab-cache.js +44 -0
- package/dist/query/vocab-cache.js.map +1 -0
- package/dist/query/vocab-validator.d.ts +71 -0
- package/dist/query/vocab-validator.d.ts.map +1 -0
- package/dist/query/vocab-validator.js +153 -0
- package/dist/query/vocab-validator.js.map +1 -0
- package/dist/utils/levenshtein.d.ts +6 -0
- package/dist/utils/levenshtein.d.ts.map +1 -0
- package/dist/utils/levenshtein.js +21 -0
- package/dist/utils/levenshtein.js.map +1 -0
- package/package.json +2 -2
- package/dist/fulltext/attach-shared.d.ts.map +0 -1
- package/dist/fulltext/attach-shared.js.map +0 -1
- package/dist/fulltext/citation-key.d.ts +0 -15
- package/dist/fulltext/citation-key.d.ts.map +0 -1
- package/dist/fulltext/citation-key.js.map +0 -1
- package/dist/fulltext/convert/index.d.ts +0 -20
- package/dist/fulltext/convert/index.d.ts.map +0 -1
- package/dist/fulltext/convert/index.js +0 -50
- package/dist/fulltext/convert/index.js.map +0 -1
- package/dist/fulltext/convert/jats-parser.d.ts +0 -36
- package/dist/fulltext/convert/jats-parser.d.ts.map +0 -1
- package/dist/fulltext/convert/jats-parser.js +0 -887
- package/dist/fulltext/convert/jats-parser.js.map +0 -1
- package/dist/fulltext/convert/markdown-writer.d.ts +0 -6
- package/dist/fulltext/convert/markdown-writer.d.ts.map +0 -1
- package/dist/fulltext/convert/markdown-writer.js.map +0 -1
- package/dist/fulltext/convert/types.d.ts +0 -141
- package/dist/fulltext/convert/types.d.ts.map +0 -1
- package/dist/fulltext/discovery/arxiv.d.ts +0 -11
- package/dist/fulltext/discovery/arxiv.d.ts.map +0 -1
- package/dist/fulltext/discovery/arxiv.js.map +0 -1
- package/dist/fulltext/discovery/core.d.ts +0 -11
- package/dist/fulltext/discovery/core.d.ts.map +0 -1
- package/dist/fulltext/discovery/core.js.map +0 -1
- package/dist/fulltext/discovery/index.d.ts +0 -28
- package/dist/fulltext/discovery/index.d.ts.map +0 -1
- package/dist/fulltext/discovery/index.js +0 -75
- package/dist/fulltext/discovery/index.js.map +0 -1
- package/dist/fulltext/discovery/pmc.d.ts +0 -19
- package/dist/fulltext/discovery/pmc.d.ts.map +0 -1
- package/dist/fulltext/discovery/pmc.js.map +0 -1
- package/dist/fulltext/discovery/unpaywall.d.ts +0 -11
- package/dist/fulltext/discovery/unpaywall.d.ts.map +0 -1
- package/dist/fulltext/discovery/unpaywall.js.map +0 -1
- package/dist/fulltext/download/downloader.d.ts +0 -21
- package/dist/fulltext/download/downloader.d.ts.map +0 -1
- package/dist/fulltext/download/downloader.js +0 -59
- package/dist/fulltext/download/downloader.js.map +0 -1
- package/dist/fulltext/download/orchestrator.d.ts +0 -33
- package/dist/fulltext/download/orchestrator.d.ts.map +0 -1
- package/dist/fulltext/download/orchestrator.js +0 -125
- package/dist/fulltext/download/orchestrator.js.map +0 -1
- package/dist/fulltext/download/pmc-xml.d.ts +0 -13
- package/dist/fulltext/download/pmc-xml.d.ts.map +0 -1
- package/dist/fulltext/download/pmc-xml.js.map +0 -1
- package/dist/fulltext/meta.d.ts +0 -25
- package/dist/fulltext/meta.d.ts.map +0 -1
- package/dist/fulltext/meta.js.map +0 -1
- package/dist/fulltext/paths.d.ts +0 -12
- package/dist/fulltext/paths.d.ts.map +0 -1
- package/dist/fulltext/paths.js.map +0 -1
- package/dist/fulltext/readme.d.ts +0 -4
- package/dist/fulltext/readme.d.ts.map +0 -1
- package/dist/fulltext/readme.js.map +0 -1
- package/dist/fulltext/types.d.ts +0 -90
- package/dist/fulltext/types.d.ts.map +0 -1
- /package/dist/{fulltext → integration}/attach-shared.js +0 -0
- /package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/paths.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sources":["../../../../src/cli/commands/fulltext/init.ts"],"sourcesContent":["/**\n * fulltext init command - Create directories for included articles.\n */\n\nimport { join } from 'node:path';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { randomUUID } from 'node:crypto';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\nimport type { ReviewFile } from '../review/types.js';\nimport
|
|
1
|
+
{"version":3,"file":"init.js","sources":["../../../../src/cli/commands/fulltext/init.ts"],"sourcesContent":["/**\n * fulltext init command - Create directories for included articles.\n */\n\nimport { join } from 'node:path';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { randomUUID } from 'node:crypto';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\nimport type { ReviewFile } from '../review/types.js';\nimport { generateCitationKey, generateDirName, createMeta, saveMeta, generateReadme, getFulltextDir, getArticleDir, getMetaPath, getReadmePath, type ArticleFulltextRef } from '@ncukondo/academic-fulltext';\n\nexport interface FulltextInitOptions {\n sessionId: string;\n sessionsDir: string;\n dryRun?: boolean;\n}\n\nexport interface FulltextInitEntry {\n dirName: string;\n citationKey: string;\n title: string;\n doi?: string;\n pmid?: string;\n}\n\nexport interface FulltextInitResult {\n created: number;\n skipped: number;\n entries: FulltextInitEntry[];\n dryRun?: boolean;\n}\n\nexport async function executeFulltextInit(\n options: FulltextInitOptions,\n): Promise<FulltextInitResult> {\n const { sessionId, sessionsDir, dryRun } = options;\n const sessionDir = join(sessionsDir, sessionId);\n\n // Load reviews.yaml\n const reviewsPath = join(sessionDir, '.internal', 'reviews.yaml');\n const reviewContent = await readFile(reviewsPath, 'utf-8');\n const reviewFile = parseYaml(reviewContent) as ReviewFile;\n\n // Filter to included articles\n const includedArticles = (reviewFile.articles ?? []).filter(\n (a) => a.finalDecision === 'include',\n );\n\n // Collect existing dirNames from reviews for skip detection\n const existingDirNames = new Set<string>();\n for (const article of reviewFile.articles ?? []) {\n if (article.fulltext?.dirName) {\n existingDirNames.add(article.fulltext.dirName);\n }\n }\n\n const entries: FulltextInitEntry[] = [];\n const existingKeys: string[] = [];\n let created = 0;\n let skipped = 0;\n\n // Track which articles in reviewFile to update with fulltext refs\n const fulltextUpdates = new Map<number, ArticleFulltextRef>();\n\n for (let i = 0; i < includedArticles.length; i++) {\n const article = includedArticles[i]!;\n\n // Find the article's index in the full review file (including non-included)\n const reviewIndex = reviewFile.articles.indexOf(article);\n\n // Skip if already has a fulltext directory\n if (article.fulltext?.dirName && existingDirNames.has(article.fulltext.dirName)) {\n skipped++;\n continue;\n }\n\n // Generate citation key and directory name\n const citationKey = generateCitationKey(article.authors, article.year, existingKeys);\n existingKeys.push(citationKey);\n\n const uuid = randomUUID();\n const dirName = generateDirName(citationKey, uuid);\n\n // Create meta\n const metaOpts: Parameters<typeof createMeta>[0] = {\n citationKey,\n uuid,\n title: article.title,\n };\n if (article.doi) metaOpts.doi = article.doi;\n if (article.pmid) metaOpts.pmid = article.pmid;\n if (article.arxivId) metaOpts.arxivId = article.arxivId;\n if (article.authors) metaOpts.authors = article.authors;\n if (article.year) metaOpts.year = article.year;\n const meta = createMeta(metaOpts);\n\n // Build fulltext ref for reviews.yaml\n const fulltextRef: ArticleFulltextRef = {\n dirName,\n hasFiles: { pdf: false, xml: false, html: false, markdown: false },\n };\n\n if (!dryRun) {\n // Create directory\n const articleDir = getArticleDir(sessionDir, dirName);\n await mkdir(articleDir, { recursive: true });\n\n // Write meta.json\n await saveMeta(getMetaPath(sessionDir, dirName), meta);\n\n // Write README.md\n const readme = generateReadme(meta);\n await writeFile(getReadmePath(sessionDir, dirName), readme, 'utf-8');\n\n // Track review update\n fulltextUpdates.set(reviewIndex, fulltextRef);\n }\n\n created++;\n const entry: FulltextInitEntry = { dirName, citationKey, title: article.title };\n if (article.doi) entry.doi = article.doi;\n if (article.pmid) entry.pmid = article.pmid;\n entries.push(entry);\n }\n\n if (!dryRun) {\n // Ensure fulltext directory exists\n await mkdir(getFulltextDir(sessionDir), { recursive: true });\n\n // Update reviews.yaml with fulltext references\n if (fulltextUpdates.size > 0) {\n for (const [reviewIdx, ref] of fulltextUpdates) {\n reviewFile.articles[reviewIdx]!.fulltext = ref;\n }\n await writeFile(reviewsPath, stringifyYaml(reviewFile), 'utf-8');\n }\n }\n\n return {\n created,\n skipped,\n entries,\n ...(dryRun && { dryRun: true }),\n };\n}\n"],"names":["parseYaml","stringifyYaml"],"mappings":";;;;;;;;;AAgCA,eAAsB,oBACpB,SAC6B;AAC7B,QAAM,EAAE,WAAW,aAAa,OAAA,IAAW;AAC3C,QAAM,aAAa,KAAK,aAAa,SAAS;AAG9C,QAAM,cAAc,KAAK,YAAY,aAAa,cAAc;AAChE,QAAM,gBAAgB,MAAM,SAAS,aAAa,OAAO;AACzD,QAAM,aAAaA,MAAU,aAAa;AAG1C,QAAM,oBAAoB,WAAW,YAAY,CAAA,GAAI;AAAA,IACnD,CAAC,MAAM,EAAE,kBAAkB;AAAA,EAAA;AAI7B,QAAM,uCAAuB,IAAA;AAC7B,aAAW,WAAW,WAAW,YAAY,CAAA,GAAI;AAC/C,QAAI,QAAQ,UAAU,SAAS;AAC7B,uBAAiB,IAAI,QAAQ,SAAS,OAAO;AAAA,IAC/C;AAAA,EACF;AAEA,QAAM,UAA+B,CAAA;AACrC,QAAM,eAAyB,CAAA;AAC/B,MAAI,UAAU;AACd,MAAI,UAAU;AAGd,QAAM,sCAAsB,IAAA;AAE5B,WAAS,IAAI,GAAG,IAAI,iBAAiB,QAAQ,KAAK;AAChD,UAAM,UAAU,iBAAiB,CAAC;AAGlC,UAAM,cAAc,WAAW,SAAS,QAAQ,OAAO;AAGvD,QAAI,QAAQ,UAAU,WAAW,iBAAiB,IAAI,QAAQ,SAAS,OAAO,GAAG;AAC/E;AACA;AAAA,IACF;AAGA,UAAM,cAAc,oBAAoB,QAAQ,SAAS,QAAQ,MAAM,YAAY;AACnF,iBAAa,KAAK,WAAW;AAE7B,UAAM,OAAO,WAAA;AACb,UAAM,UAAU,gBAAgB,aAAa,IAAI;AAGjD,UAAM,WAA6C;AAAA,MACjD;AAAA,MACA;AAAA,MACA,OAAO,QAAQ;AAAA,IAAA;AAEjB,QAAI,QAAQ,IAAK,UAAS,MAAM,QAAQ;AACxC,QAAI,QAAQ,KAAM,UAAS,OAAO,QAAQ;AAC1C,QAAI,QAAQ,QAAS,UAAS,UAAU,QAAQ;AAChD,QAAI,QAAQ,QAAS,UAAS,UAAU,QAAQ;AAChD,QAAI,QAAQ,KAAM,UAAS,OAAO,QAAQ;AAC1C,UAAM,OAAO,WAAW,QAAQ;AAGhC,UAAM,cAAkC;AAAA,MACtC;AAAA,MACA,UAAU,EAAE,KAAK,OAAO,KAAK,OAAO,MAAM,OAAO,UAAU,MAAA;AAAA,IAAM;AAGnE,QAAI,CAAC,QAAQ;AAEX,YAAM,aAAa,cAAc,YAAY,OAAO;AACpD,YAAM,MAAM,YAAY,EAAE,WAAW,MAAM;AAG3C,YAAM,SAAS,YAAY,YAAY,OAAO,GAAG,IAAI;AAGrD,YAAM,SAAS,eAAe,IAAI;AAClC,YAAM,UAAU,cAAc,YAAY,OAAO,GAAG,QAAQ,OAAO;AAGnE,sBAAgB,IAAI,aAAa,WAAW;AAAA,IAC9C;AAEA;AACA,UAAM,QAA2B,EAAE,SAAS,aAAa,OAAO,QAAQ,MAAA;AACxE,QAAI,QAAQ,IAAK,OAAM,MAAM,QAAQ;AACrC,QAAI,QAAQ,KAAM,OAAM,OAAO,QAAQ;AACvC,YAAQ,KAAK,KAAK;AAAA,EACpB;AAEA,MAAI,CAAC,QAAQ;AAEX,UAAM,MAAM,eAAe,UAAU,GAAG,EAAE,WAAW,MAAM;AAG3D,QAAI,gBAAgB,OAAO,GAAG;AAC5B,iBAAW,CAAC,WAAW,GAAG,KAAK,iBAAiB;AAC9C,mBAAW,SAAS,SAAS,EAAG,WAAW;AAAA,MAC7C;AACA,YAAM,UAAU,aAAaC,UAAc,UAAU,GAAG,OAAO;AAAA,IACjE;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,UAAU,EAAE,QAAQ,KAAA;AAAA,EAAK;AAEjC;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pending.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/fulltext/pending.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"pending.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/fulltext/pending.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAGrF,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAyDD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,CA0BnE;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAuChC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { parse } from "yaml";
|
|
4
|
-
import { loadMeta } from "../../../fulltext/meta.js";
|
|
5
|
-
import { getMetaPath } from "../../../fulltext/paths.js";
|
|
4
|
+
import { loadMeta } from "../../../node_modules/@ncukondo/academic-fulltext/dist/meta.js";
|
|
5
|
+
import { getMetaPath } from "../../../node_modules/@ncukondo/academic-fulltext/dist/paths.js";
|
|
6
|
+
import "../../../node_modules/@ncukondo/academic-fulltext/dist/convert/jats-parser.js";
|
|
7
|
+
import "node:crypto";
|
|
6
8
|
async function hasFulltextFiles(sessionDir, dirName) {
|
|
7
9
|
try {
|
|
8
10
|
const metaPath = getMetaPath(sessionDir, dirName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pending.js","sources":["../../../../src/cli/commands/fulltext/pending.ts"],"sourcesContent":["/**\n * Fulltext pending command.\n * Lists articles needing manual download with URLs.\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { loadMeta
|
|
1
|
+
{"version":3,"file":"pending.js","sources":["../../../../src/cli/commands/fulltext/pending.ts"],"sourcesContent":["/**\n * Fulltext pending command.\n * Lists articles needing manual download with URLs.\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { loadMeta, getMetaPath, type OALocation } from '@ncukondo/academic-fulltext';\nimport type { ReviewFile, ArticleEntry } from '../review/types.js';\n\nexport interface FulltextPendingOptions {\n sessionDir: string;\n format?: 'table' | 'json';\n exportPath?: string | undefined;\n}\n\nexport interface PendingArticle {\n dirName?: string;\n citationKey?: string;\n title: string;\n doi?: string;\n pmid?: string;\n publisherUrl?: string;\n oaLocations?: OALocation[];\n}\n\nexport interface FulltextPendingResult {\n totalPending: number;\n articles: PendingArticle[];\n}\n\n/**\n * Check if an article has any fulltext files by reading its meta.json.\n */\nasync function hasFulltextFiles(\n sessionDir: string,\n dirName: string,\n): Promise<boolean> {\n try {\n const metaPath = getMetaPath(sessionDir, dirName);\n const meta = await loadMeta(metaPath);\n return (\n meta.files.pdf !== undefined ||\n meta.files.markdown !== undefined\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Build a PendingArticle from an ArticleEntry, enriched with meta.json data.\n */\nasync function buildPendingArticle(\n article: ArticleEntry,\n sessionDir: string,\n): Promise<PendingArticle> {\n const pending: PendingArticle = {\n title: article.title,\n };\n\n if (article.doi) {\n pending.doi = article.doi;\n pending.publisherUrl = `https://doi.org/${article.doi}`;\n }\n if (article.pmid) pending.pmid = article.pmid;\n\n if (article.fulltext?.dirName) {\n pending.dirName = article.fulltext.dirName;\n\n // Try to load meta.json for OA locations and citation key\n try {\n const metaPath = getMetaPath(sessionDir, article.fulltext.dirName);\n const meta = await loadMeta(metaPath);\n pending.citationKey = meta.citationKey;\n if (meta.oaLocations && meta.oaLocations.length > 0) {\n pending.oaLocations = meta.oaLocations;\n }\n } catch {\n // meta.json not readable — skip enrichment\n }\n }\n\n return pending;\n}\n\n/**\n * Format the export file content for batch download.\n * Format: comment line with article identifier, followed by URL lines.\n */\nexport function formatExportFile(articles: PendingArticle[]): string {\n const blocks: string[] = [];\n\n for (const article of articles) {\n const identifier = article.dirName ?? article.title;\n const header = identifier === article.title\n ? `# ${article.title}`\n : `# ${identifier} - ${article.title}`;\n const lines: string[] = [header];\n\n // Publisher URL (DOI link) first\n if (article.publisherUrl) {\n lines.push(article.publisherUrl);\n }\n\n // OA location URLs\n if (article.oaLocations) {\n for (const loc of article.oaLocations) {\n lines.push(loc.url);\n }\n }\n\n blocks.push(lines.join('\\n'));\n }\n\n return blocks.join('\\n\\n') + '\\n';\n}\n\n/**\n * Execute the fulltext pending command.\n * Lists included articles that don't yet have fulltext files.\n */\nexport async function executeFulltextPending(\n options: FulltextPendingOptions,\n): Promise<FulltextPendingResult> {\n const { sessionDir, exportPath } = options;\n\n // Load reviews.yaml\n const reviewsPath = join(sessionDir, '.internal', 'reviews.yaml');\n const content = await readFile(reviewsPath, 'utf-8');\n const reviewFile = parseYaml(content) as ReviewFile;\n\n // Filter to included articles\n const included = (reviewFile.articles ?? []).filter(\n (a) => a.finalDecision === 'include',\n );\n\n const articles: PendingArticle[] = [];\n\n for (const article of included) {\n // Articles with no fulltext ref are not initialized — always pending\n if (!article.fulltext?.dirName) {\n articles.push(await buildPendingArticle(article, sessionDir));\n continue;\n }\n\n // Articles with a directory but no files are pending\n const hasFiles = await hasFulltextFiles(sessionDir, article.fulltext.dirName);\n if (!hasFiles) {\n articles.push(await buildPendingArticle(article, sessionDir));\n }\n }\n\n // Write export file if requested\n if (exportPath && articles.length > 0) {\n const exportContent = formatExportFile(articles);\n await writeFile(exportPath, exportContent, 'utf-8');\n }\n\n return {\n totalPending: articles.length,\n articles,\n };\n}\n"],"names":["parseYaml"],"mappings":";;;;;;;AAmCA,eAAe,iBACb,YACA,SACkB;AAClB,MAAI;AACF,UAAM,WAAW,YAAY,YAAY,OAAO;AAChD,UAAM,OAAO,MAAM,SAAS,QAAQ;AACpC,WACE,KAAK,MAAM,QAAQ,UACnB,KAAK,MAAM,aAAa;AAAA,EAE5B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKA,eAAe,oBACb,SACA,YACyB;AACzB,QAAM,UAA0B;AAAA,IAC9B,OAAO,QAAQ;AAAA,EAAA;AAGjB,MAAI,QAAQ,KAAK;AACf,YAAQ,MAAM,QAAQ;AACtB,YAAQ,eAAe,mBAAmB,QAAQ,GAAG;AAAA,EACvD;AACA,MAAI,QAAQ,KAAM,SAAQ,OAAO,QAAQ;AAEzC,MAAI,QAAQ,UAAU,SAAS;AAC7B,YAAQ,UAAU,QAAQ,SAAS;AAGnC,QAAI;AACF,YAAM,WAAW,YAAY,YAAY,QAAQ,SAAS,OAAO;AACjE,YAAM,OAAO,MAAM,SAAS,QAAQ;AACpC,cAAQ,cAAc,KAAK;AAC3B,UAAI,KAAK,eAAe,KAAK,YAAY,SAAS,GAAG;AACnD,gBAAQ,cAAc,KAAK;AAAA,MAC7B;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,iBAAiB,UAAoC;AACnE,QAAM,SAAmB,CAAA;AAEzB,aAAW,WAAW,UAAU;AAC9B,UAAM,aAAa,QAAQ,WAAW,QAAQ;AAC9C,UAAM,SAAS,eAAe,QAAQ,QAClC,KAAK,QAAQ,KAAK,KAClB,KAAK,UAAU,MAAM,QAAQ,KAAK;AACtC,UAAM,QAAkB,CAAC,MAAM;AAG/B,QAAI,QAAQ,cAAc;AACxB,YAAM,KAAK,QAAQ,YAAY;AAAA,IACjC;AAGA,QAAI,QAAQ,aAAa;AACvB,iBAAW,OAAO,QAAQ,aAAa;AACrC,cAAM,KAAK,IAAI,GAAG;AAAA,MACpB;AAAA,IACF;AAEA,WAAO,KAAK,MAAM,KAAK,IAAI,CAAC;AAAA,EAC9B;AAEA,SAAO,OAAO,KAAK,MAAM,IAAI;AAC/B;AAMA,eAAsB,uBACpB,SACgC;AAChC,QAAM,EAAE,YAAY,WAAA,IAAe;AAGnC,QAAM,cAAc,KAAK,YAAY,aAAa,cAAc;AAChE,QAAM,UAAU,MAAM,SAAS,aAAa,OAAO;AACnD,QAAM,aAAaA,MAAU,OAAO;AAGpC,QAAM,YAAY,WAAW,YAAY,CAAA,GAAI;AAAA,IAC3C,CAAC,MAAM,EAAE,kBAAkB;AAAA,EAAA;AAG7B,QAAM,WAA6B,CAAA;AAEnC,aAAW,WAAW,UAAU;AAE9B,QAAI,CAAC,QAAQ,UAAU,SAAS;AAC9B,eAAS,KAAK,MAAM,oBAAoB,SAAS,UAAU,CAAC;AAC5D;AAAA,IACF;AAGA,UAAM,WAAW,MAAM,iBAAiB,YAAY,QAAQ,SAAS,OAAO;AAC5E,QAAI,CAAC,UAAU;AACb,eAAS,KAAK,MAAM,oBAAoB,SAAS,UAAU,CAAC;AAAA,IAC9D;AAAA,EACF;AAGA,MAAI,cAAc,SAAS,SAAS,GAAG;AACrC,UAAM,gBAAgB,iBAAiB,QAAQ;AAC/C,UAAM,UAAU,YAAY,eAAe,OAAO;AAAA,EACpD;AAEA,SAAO;AAAA,IACL,cAAc,SAAS;AAAA,IACvB;AAAA,EAAA;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/fulltext/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/fulltext/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AA+BD;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAgD/B"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { parse } from "yaml";
|
|
4
|
-
import { loadMeta } from "../../../fulltext/meta.js";
|
|
5
|
-
import { getMetaPath } from "../../../fulltext/paths.js";
|
|
4
|
+
import { loadMeta } from "../../../node_modules/@ncukondo/academic-fulltext/dist/meta.js";
|
|
5
|
+
import { getMetaPath } from "../../../node_modules/@ncukondo/academic-fulltext/dist/paths.js";
|
|
6
|
+
import "../../../node_modules/@ncukondo/academic-fulltext/dist/convert/jats-parser.js";
|
|
7
|
+
import "node:crypto";
|
|
6
8
|
async function classifyArticle(article, sessionDir) {
|
|
7
9
|
if (!article.fulltext?.dirName) {
|
|
8
10
|
return "not-initialized";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sources":["../../../../src/cli/commands/fulltext/status.ts"],"sourcesContent":["/**\n * Fulltext status command.\n * Shows overall fulltext retrieval status for a session.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { loadMeta
|
|
1
|
+
{"version":3,"file":"status.js","sources":["../../../../src/cli/commands/fulltext/status.ts"],"sourcesContent":["/**\n * Fulltext status command.\n * Shows overall fulltext retrieval status for a session.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { loadMeta, getMetaPath } from '@ncukondo/academic-fulltext';\nimport type { ReviewFile, ArticleEntry } from '../review/types.js';\n\nexport interface FulltextStatusOptions {\n sessionDir: string;\n format?: 'table' | 'json';\n}\n\nexport interface FulltextStatusResult {\n totalIncluded: number;\n withFulltext: number;\n pdfOnly: number;\n markdownOnly: number;\n both: number;\n pending: number;\n notInitialized: number;\n}\n\n/**\n * Classify an article's fulltext state by reading its meta.json.\n * Returns: 'pdf-only' | 'markdown-only' | 'both' | 'pending' | 'not-initialized'\n */\nasync function classifyArticle(\n article: ArticleEntry,\n sessionDir: string,\n): Promise<'pdf-only' | 'markdown-only' | 'both' | 'pending' | 'not-initialized'> {\n if (!article.fulltext?.dirName) {\n return 'not-initialized';\n }\n\n try {\n const metaPath = getMetaPath(sessionDir, article.fulltext.dirName);\n const meta = await loadMeta(metaPath);\n\n const hasPdf = meta.files.pdf !== undefined;\n const hasMd = meta.files.markdown !== undefined;\n\n if (hasPdf && hasMd) return 'both';\n if (hasPdf) return 'pdf-only';\n if (hasMd) return 'markdown-only';\n return 'pending';\n } catch {\n // Can't read meta.json — treat as pending since directory was assigned\n return 'pending';\n }\n}\n\n/**\n * Execute the fulltext status command.\n * Scans included articles and reports fulltext retrieval status.\n */\nexport async function executeFulltextStatus(\n options: FulltextStatusOptions,\n): Promise<FulltextStatusResult> {\n const { sessionDir } = options;\n\n // Load reviews.yaml\n const reviewsPath = join(sessionDir, '.internal', 'reviews.yaml');\n const content = await readFile(reviewsPath, 'utf-8');\n const reviewFile = parseYaml(content) as ReviewFile;\n\n // Filter to included articles\n const included = (reviewFile.articles ?? []).filter(\n (a) => a.finalDecision === 'include',\n );\n\n const result: FulltextStatusResult = {\n totalIncluded: included.length,\n withFulltext: 0,\n pdfOnly: 0,\n markdownOnly: 0,\n both: 0,\n pending: 0,\n notInitialized: 0,\n };\n\n for (const article of included) {\n const state = await classifyArticle(article, sessionDir);\n switch (state) {\n case 'pdf-only':\n result.pdfOnly++;\n result.withFulltext++;\n break;\n case 'markdown-only':\n result.markdownOnly++;\n result.withFulltext++;\n break;\n case 'both':\n result.both++;\n result.withFulltext++;\n break;\n case 'pending':\n result.pending++;\n break;\n case 'not-initialized':\n result.notInitialized++;\n break;\n }\n }\n\n return result;\n}\n"],"names":["parseYaml"],"mappings":";;;;;;;AA8BA,eAAe,gBACb,SACA,YACgF;AAChF,MAAI,CAAC,QAAQ,UAAU,SAAS;AAC9B,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,WAAW,YAAY,YAAY,QAAQ,SAAS,OAAO;AACjE,UAAM,OAAO,MAAM,SAAS,QAAQ;AAEpC,UAAM,SAAS,KAAK,MAAM,QAAQ;AAClC,UAAM,QAAQ,KAAK,MAAM,aAAa;AAEtC,QAAI,UAAU,MAAO,QAAO;AAC5B,QAAI,OAAQ,QAAO;AACnB,QAAI,MAAO,QAAO;AAClB,WAAO;AAAA,EACT,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAMA,eAAsB,sBACpB,SAC+B;AAC/B,QAAM,EAAE,eAAe;AAGvB,QAAM,cAAc,KAAK,YAAY,aAAa,cAAc;AAChE,QAAM,UAAU,MAAM,SAAS,aAAa,OAAO;AACnD,QAAM,aAAaA,MAAU,OAAO;AAGpC,QAAM,YAAY,WAAW,YAAY,CAAA,GAAI;AAAA,IAC3C,CAAC,MAAM,EAAE,kBAAkB;AAAA,EAAA;AAG7B,QAAM,SAA+B;AAAA,IACnC,eAAe,SAAS;AAAA,IACxB,cAAc;AAAA,IACd,SAAS;AAAA,IACT,cAAc;AAAA,IACd,MAAM;AAAA,IACN,SAAS;AAAA,IACT,gBAAgB;AAAA,EAAA;AAGlB,aAAW,WAAW,UAAU;AAC9B,UAAM,QAAQ,MAAM,gBAAgB,SAAS,UAAU;AACvD,YAAQ,OAAA;AAAA,MACN,KAAK;AACH,eAAO;AACP,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,IAAA;AAAA,EAEN;AAEA,SAAO;AACT;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/fulltext/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/fulltext/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgBH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CAqI7B"}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { readdir, stat, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { parse, stringify } from "yaml";
|
|
4
|
-
import { loadMeta, updateMetaFiles, saveMeta } from "../../../fulltext/meta.js";
|
|
5
|
-
import { getFulltextDir } from "../../../fulltext/paths.js";
|
|
4
|
+
import { loadMeta, updateMetaFiles, saveMeta } from "../../../node_modules/@ncukondo/academic-fulltext/dist/meta.js";
|
|
5
|
+
import { getFulltextDir } from "../../../node_modules/@ncukondo/academic-fulltext/dist/paths.js";
|
|
6
|
+
import "../../../node_modules/@ncukondo/academic-fulltext/dist/convert/jats-parser.js";
|
|
7
|
+
import "node:crypto";
|
|
6
8
|
const FULLTEXT_FILES = {
|
|
7
9
|
"fulltext.pdf": "pdf",
|
|
8
10
|
"fulltext.xml": "xml",
|
|
11
|
+
"fulltext.html": "html",
|
|
9
12
|
"fulltext.md": "markdown"
|
|
10
13
|
};
|
|
11
14
|
async function executeFulltextSync(options) {
|
|
@@ -72,6 +75,7 @@ async function executeFulltextSync(options) {
|
|
|
72
75
|
const hasFiles = {
|
|
73
76
|
pdf: !!updatedMeta.files.pdf,
|
|
74
77
|
xml: !!updatedMeta.files.xml,
|
|
78
|
+
html: !!updatedMeta.files.html,
|
|
75
79
|
markdown: !!updatedMeta.files.markdown
|
|
76
80
|
};
|
|
77
81
|
hasFilesUpdates.set(dirName, hasFiles);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sources":["../../../../src/cli/commands/fulltext/sync.ts"],"sourcesContent":["/**\n * fulltext sync command - Detect and register manually added files.\n */\n\nimport { join } from 'node:path';\nimport { readFile, writeFile, readdir, stat } from 'node:fs/promises';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\nimport type { ReviewFile } from '../review/types.js';\nimport
|
|
1
|
+
{"version":3,"file":"sync.js","sources":["../../../../src/cli/commands/fulltext/sync.ts"],"sourcesContent":["/**\n * fulltext sync command - Detect and register manually added files.\n */\n\nimport { join } from 'node:path';\nimport { readFile, writeFile, readdir, stat } from 'node:fs/promises';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\nimport type { ReviewFile } from '../review/types.js';\nimport { loadMeta, saveMeta, updateMetaFiles, getFulltextDir, type FulltextMeta, type FileInfo } from '@ncukondo/academic-fulltext';\n\n/** Known fulltext filenames and their type keys. */\nconst FULLTEXT_FILES: Record<string, 'pdf' | 'xml' | 'html' | 'markdown'> = {\n 'fulltext.pdf': 'pdf',\n 'fulltext.xml': 'xml',\n 'fulltext.html': 'html',\n 'fulltext.md': 'markdown',\n};\n\nexport interface FulltextSyncOptions {\n sessionId: string;\n sessionsDir: string;\n dryRun?: boolean;\n}\n\nexport interface FulltextSyncEntry {\n dirName: string;\n files: string[];\n sizes: number[];\n}\n\nexport interface FulltextSyncResult {\n /** Total number of new files synced */\n synced: number;\n /** Number of articles updated */\n articlesUpdated: number;\n entries: FulltextSyncEntry[];\n dryRun?: boolean;\n}\n\nexport async function executeFulltextSync(\n options: FulltextSyncOptions,\n): Promise<FulltextSyncResult> {\n const { sessionId, sessionsDir, dryRun } = options;\n const sessionDir = join(sessionsDir, sessionId);\n const fulltextDir = getFulltextDir(sessionDir);\n\n // Scan all directories in fulltext/\n let dirEntries: string[];\n try {\n const entries = await readdir(fulltextDir, { withFileTypes: true });\n dirEntries = entries.filter(e => e.isDirectory()).map(e => e.name);\n } catch {\n return { synced: 0, articlesUpdated: 0, entries: [] };\n }\n\n const syncEntries: FulltextSyncEntry[] = [];\n let totalSynced = 0;\n const articlesWithChanges = new Set<string>();\n\n // Track updates for meta and reviews\n const hasFilesUpdates = new Map<string, { pdf: boolean; xml: boolean; html: boolean; markdown: boolean }>();\n const metaUpdates = new Map<string, { meta: FulltextMeta; path: string }>();\n\n for (const dirName of dirEntries) {\n const articleDir = join(fulltextDir, dirName);\n const metaPath = join(articleDir, 'meta.json');\n\n // Load meta.json\n let meta: FulltextMeta;\n try {\n meta = await loadMeta(metaPath);\n } catch {\n // Skip directories without meta.json\n continue;\n }\n\n const newFiles: string[] = [];\n const newSizes: number[] = [];\n const fileInfoUpdates: { pdf?: FileInfo; xml?: FileInfo; html?: FileInfo; markdown?: FileInfo } = {};\n\n for (const [filename, typeKey] of Object.entries(FULLTEXT_FILES)) {\n // Skip if already tracked in meta\n if (meta.files[typeKey]) {\n continue;\n }\n\n // Check if file exists\n const filePath = join(articleDir, filename);\n let fileStat;\n try {\n fileStat = await stat(filePath);\n } catch {\n continue; // File doesn't exist\n }\n\n if (!fileStat.isFile()) continue;\n\n // New file found\n const fileInfo: FileInfo = {\n filename,\n source: 'manual',\n retrievedAt: new Date().toISOString(),\n size: fileStat.size,\n };\n\n fileInfoUpdates[typeKey] = fileInfo;\n newFiles.push(filename);\n newSizes.push(fileStat.size);\n }\n\n if (newFiles.length > 0) {\n totalSynced += newFiles.length;\n articlesWithChanges.add(dirName);\n\n syncEntries.push({\n dirName,\n files: newFiles,\n sizes: newSizes,\n });\n\n if (!dryRun) {\n // Update meta.json\n const updatedMeta = updateMetaFiles(meta, fileInfoUpdates);\n metaUpdates.set(dirName, { meta: updatedMeta, path: metaPath });\n\n // Compute updated hasFiles for reviews\n const hasFiles = {\n pdf: !!(updatedMeta.files.pdf),\n xml: !!(updatedMeta.files.xml),\n html: !!(updatedMeta.files.html),\n markdown: !!(updatedMeta.files.markdown),\n };\n hasFilesUpdates.set(dirName, hasFiles);\n }\n }\n }\n\n if (!dryRun && metaUpdates.size > 0) {\n // Save all meta.json updates\n for (const [, { meta, path }] of metaUpdates) {\n await saveMeta(path, meta);\n }\n\n // Update reviews.yaml if it exists\n const reviewsPath = join(sessionDir, '.internal', 'reviews.yaml');\n try {\n const reviewContent = await readFile(reviewsPath, 'utf-8');\n const reviewFile = parseYaml(reviewContent) as ReviewFile;\n let reviewsChanged = false;\n\n for (const article of reviewFile.articles) {\n if (article.fulltext?.dirName && hasFilesUpdates.has(article.fulltext.dirName)) {\n const hasFiles = hasFilesUpdates.get(article.fulltext.dirName);\n if (hasFiles) {\n article.fulltext.hasFiles = hasFiles;\n reviewsChanged = true;\n }\n }\n }\n\n if (reviewsChanged) {\n await writeFile(reviewsPath, stringifyYaml(reviewFile), 'utf-8');\n }\n } catch {\n // No reviews.yaml - that's fine\n }\n }\n\n return {\n synced: totalSynced,\n articlesUpdated: articlesWithChanges.size,\n entries: syncEntries,\n ...(dryRun && { dryRun: true }),\n };\n}\n"],"names":["parseYaml","stringifyYaml"],"mappings":"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"}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The YAML template string with comments preserved.
|
|
3
|
+
* This is a raw string (not generated by a YAML library) so comments are kept.
|
|
4
|
+
*/
|
|
5
|
+
export declare const QUERY_SCHEMA_FILENAME = "query.schema.json";
|
|
1
6
|
/**
|
|
2
7
|
* Generate the query template YAML string.
|
|
3
8
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/query/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/query/init.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAiDzD;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAkCjD"}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { access, writeFile } from "node:fs/promises";
|
|
2
|
-
|
|
2
|
+
import { join, dirname } from "node:path";
|
|
3
|
+
import { generateQueryJSONSchema } from "../../../query/json-schema.js";
|
|
4
|
+
const QUERY_SCHEMA_FILENAME = "query.schema.json";
|
|
5
|
+
const QUERY_TEMPLATE = `# yaml-language-server: $schema=./${QUERY_SCHEMA_FILENAME}
|
|
6
|
+
name: my_search
|
|
3
7
|
description: ""
|
|
4
8
|
|
|
5
9
|
query:
|
|
@@ -62,12 +66,16 @@ async function writeQueryTemplate(options) {
|
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
await writeFile(options.output, template, "utf-8");
|
|
69
|
+
const schemaPath = join(dirname(options.output), QUERY_SCHEMA_FILENAME);
|
|
70
|
+
const jsonSchema = generateQueryJSONSchema();
|
|
71
|
+
await writeFile(schemaPath, JSON.stringify(jsonSchema, null, 2) + "\n", "utf-8");
|
|
65
72
|
return {
|
|
66
73
|
success: true,
|
|
67
74
|
message: `Template written to ${options.output}`
|
|
68
75
|
};
|
|
69
76
|
}
|
|
70
77
|
export {
|
|
78
|
+
QUERY_SCHEMA_FILENAME,
|
|
71
79
|
generateQueryTemplate,
|
|
72
80
|
writeQueryTemplate
|
|
73
81
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sources":["../../../../src/cli/commands/query/init.ts"],"sourcesContent":["/**\n * Query init command implementation.\n *\n * Generates a skeleton YAML query file with helpful comments.\n */\nimport { writeFile as fsWriteFile, access } from \"node:fs/promises\";\n\n/**\n * The YAML template string with comments preserved.\n * This is a raw string (not generated by a YAML library) so comments are kept.\n */\n// prettier-ignore\nconst QUERY_TEMPLATE =\n \"name: my_search\\n\" +\n \"description: \\\"\\\"\\n\" +\n \"\\n\" +\n \"query:\\n\" +\n \" - field: title_abstract # title, abstract, title_abstract, author, keyword, all\\n\" +\n \" terms:\\n\" +\n \" keywords:\\n\" +\n \" - \\\"search term 1\\\"\\n\" +\n \" - \\\"search term 2\\\"\\n\" +\n \" # mesh: # PubMed MeSH terms (optional)\\n\" +\n \" # - \\\"MeSH Heading\\\"\\n\" +\n \" # eric: # ERIC Descriptors (optional, ERIC only)\\n\" +\n \" # - \\\"ERIC Descriptor\\\"\\n\" +\n \" exclude: [] # Terms to exclude (NOT operator)\\n\" +\n \" # Tip: Use exclude to filter out false matches from short keywords/acronyms\\n\" +\n \" # exclude:\\n\" +\n \" # - \\\"unwanted term\\\"\\n\" +\n \" # - \\\"irrelevant topic\\\"\\n\" +\n \" operator: OR # How to combine terms within this block\\n\" +\n \"\\n\" +\n \" # Add more blocks — blocks are AND'd together\\n\" +\n \" # - field: title_abstract\\n\" +\n \" # terms:\\n\" +\n \" # keywords:\\n\" +\n \" # - \\\"another term\\\"\\n\" +\n \" # operator: OR\\n\" +\n \"\\n\" +\n \"# filters: # Optional: apply to all databases\\n\" +\n \"# year_from: 2020\\n\" +\n \"# year_to: 2026\\n\" +\n \"# language:\\n\" +\n \"# - en\\n\" +\n \"# publication_types:\\n\" +\n \"# exclude:\\n\" +\n \"# - \\\"Review\\\"\\n\" +\n \"# - \\\"Comment\\\"\\n\" +\n \"\\n\" +\n \"# overrides: # Optional: database-specific settings\\n\" +\n \"# pubmed:\\n\" +\n \"# filters:\\n\" +\n \"# publication_types:\\n\" +\n \"# exclude:\\n\" +\n \"# - \\\"Letter\\\"\\n\";\n\n/**\n * Generate the query template YAML string.\n *\n * @returns The YAML template string with comments\n */\nexport function generateQueryTemplate(): string {\n return QUERY_TEMPLATE;\n}\n\n/**\n * Write the query template to a file or return it as a message.\n *\n * @param options - Output options\n * @param options.output - File path to write to (if omitted, returns template in message)\n * @param options.force - Whether to overwrite existing files\n * @returns Result with success status and message\n */\nexport async function writeQueryTemplate(options: {\n output?: string;\n force?: boolean;\n}): Promise<{ success: boolean; message: string }> {\n const template = generateQueryTemplate();\n\n if (!options.output) {\n // No output file specified, return template as message\n return { success: true, message: template };\n }\n\n // Check if file exists (unless force is set)\n if (!options.force) {\n try {\n await access(options.output);\n // File exists and force is not set\n return {\n success: false,\n message: `File already exists: ${options.output}. Use --force to overwrite.`,\n };\n } catch {\n // File does not exist, proceed\n }\n }\n\n // Write to file\n await fsWriteFile(options.output, template, \"utf-8\");\n return {\n success: true,\n message: `Template written to ${options.output}`,\n };\n}\n"],"names":["fsWriteFile"],"mappings":";
|
|
1
|
+
{"version":3,"file":"init.js","sources":["../../../../src/cli/commands/query/init.ts"],"sourcesContent":["/**\n * Query init command implementation.\n *\n * Generates a skeleton YAML query file with helpful comments.\n */\nimport { writeFile as fsWriteFile, access } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { generateQueryJSONSchema } from \"../../../query/json-schema.js\";\n\n/**\n * The YAML template string with comments preserved.\n * This is a raw string (not generated by a YAML library) so comments are kept.\n */\nexport const QUERY_SCHEMA_FILENAME = \"query.schema.json\";\n\n// prettier-ignore\nconst QUERY_TEMPLATE =\n `# yaml-language-server: $schema=./${QUERY_SCHEMA_FILENAME}\\n` +\n \"name: my_search\\n\" +\n \"description: \\\"\\\"\\n\" +\n \"\\n\" +\n \"query:\\n\" +\n \" - field: title_abstract # title, abstract, title_abstract, author, keyword, all\\n\" +\n \" terms:\\n\" +\n \" keywords:\\n\" +\n \" - \\\"search term 1\\\"\\n\" +\n \" - \\\"search term 2\\\"\\n\" +\n \" # mesh: # PubMed MeSH terms (optional)\\n\" +\n \" # - \\\"MeSH Heading\\\"\\n\" +\n \" # eric: # ERIC Descriptors (optional, ERIC only)\\n\" +\n \" # - \\\"ERIC Descriptor\\\"\\n\" +\n \" exclude: [] # Terms to exclude (NOT operator)\\n\" +\n \" # Tip: Use exclude to filter out false matches from short keywords/acronyms\\n\" +\n \" # exclude:\\n\" +\n \" # - \\\"unwanted term\\\"\\n\" +\n \" # - \\\"irrelevant topic\\\"\\n\" +\n \" operator: OR # How to combine terms within this block\\n\" +\n \"\\n\" +\n \" # Add more blocks — blocks are AND'd together\\n\" +\n \" # - field: title_abstract\\n\" +\n \" # terms:\\n\" +\n \" # keywords:\\n\" +\n \" # - \\\"another term\\\"\\n\" +\n \" # operator: OR\\n\" +\n \"\\n\" +\n \"# filters: # Optional: apply to all databases\\n\" +\n \"# year_from: 2020\\n\" +\n \"# year_to: 2026\\n\" +\n \"# language:\\n\" +\n \"# - en\\n\" +\n \"# publication_types:\\n\" +\n \"# exclude:\\n\" +\n \"# - \\\"Review\\\"\\n\" +\n \"# - \\\"Comment\\\"\\n\" +\n \"\\n\" +\n \"# overrides: # Optional: database-specific settings\\n\" +\n \"# pubmed:\\n\" +\n \"# filters:\\n\" +\n \"# publication_types:\\n\" +\n \"# exclude:\\n\" +\n \"# - \\\"Letter\\\"\\n\";\n\n/**\n * Generate the query template YAML string.\n *\n * @returns The YAML template string with comments\n */\nexport function generateQueryTemplate(): string {\n return QUERY_TEMPLATE;\n}\n\n/**\n * Write the query template to a file or return it as a message.\n *\n * @param options - Output options\n * @param options.output - File path to write to (if omitted, returns template in message)\n * @param options.force - Whether to overwrite existing files\n * @returns Result with success status and message\n */\nexport async function writeQueryTemplate(options: {\n output?: string;\n force?: boolean;\n}): Promise<{ success: boolean; message: string }> {\n const template = generateQueryTemplate();\n\n if (!options.output) {\n // No output file specified, return template as message\n return { success: true, message: template };\n }\n\n // Check if file exists (unless force is set)\n if (!options.force) {\n try {\n await access(options.output);\n // File exists and force is not set\n return {\n success: false,\n message: `File already exists: ${options.output}. Use --force to overwrite.`,\n };\n } catch {\n // File does not exist, proceed\n }\n }\n\n // Write to file\n await fsWriteFile(options.output, template, \"utf-8\");\n\n // Generate JSON Schema file alongside output\n const schemaPath = join(dirname(options.output), QUERY_SCHEMA_FILENAME);\n const jsonSchema = generateQueryJSONSchema();\n await fsWriteFile(schemaPath, JSON.stringify(jsonSchema, null, 2) + \"\\n\", \"utf-8\");\n\n return {\n success: true,\n message: `Template written to ${options.output}`,\n };\n}\n"],"names":["fsWriteFile"],"mappings":";;;AAaO,MAAM,wBAAwB;AAGrC,MAAM,iBACJ,qCAAqC,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkDrD,SAAS,wBAAgC;AAC9C,SAAO;AACT;AAUA,eAAsB,mBAAmB,SAGU;AACjD,QAAM,WAAW,sBAAA;AAEjB,MAAI,CAAC,QAAQ,QAAQ;AAEnB,WAAO,EAAE,SAAS,MAAM,SAAS,SAAA;AAAA,EACnC;AAGA,MAAI,CAAC,QAAQ,OAAO;AAClB,QAAI;AACF,YAAM,OAAO,QAAQ,MAAM;AAE3B,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,wBAAwB,QAAQ,MAAM;AAAA,MAAA;AAAA,IAEnD,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAMA,UAAY,QAAQ,QAAQ,UAAU,OAAO;AAGnD,QAAM,aAAa,KAAK,QAAQ,QAAQ,MAAM,GAAG,qBAAqB;AACtE,QAAM,aAAa,wBAAA;AACnB,QAAMA,UAAY,YAAY,KAAK,UAAU,YAAY,MAAM,CAAC,IAAI,MAAM,OAAO;AAEjF,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS,uBAAuB,QAAQ,MAAM;AAAA,EAAA;AAElD;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/query/translate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAwBtF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAChD;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAuD1B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,MAAM,GACf,MAAM,
|
|
1
|
+
{"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/query/translate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAwBtF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAChD;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAuD1B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,MAAM,GACf,MAAM,CAqBR"}
|
|
@@ -64,6 +64,11 @@ function formatTranslateResult(result, filePath) {
|
|
|
64
64
|
for (const [provider, translation] of Object.entries(result.translations)) {
|
|
65
65
|
lines.push(`[${provider.toUpperCase()}]`);
|
|
66
66
|
lines.push(translation.native);
|
|
67
|
+
if (translation.warnings && translation.warnings.length > 0) {
|
|
68
|
+
for (const warning of translation.warnings) {
|
|
69
|
+
lines.push(`⚠ ${warning}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
67
72
|
lines.push("");
|
|
68
73
|
}
|
|
69
74
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translate.js","sources":["../../../../src/cli/commands/query/translate.ts"],"sourcesContent":["/**\n * Query translate command implementation.\n *\n * Translates a YAML query file to native database query syntax for each provider.\n */\nimport { readFile } from 'node:fs/promises';\nimport { parseQueryString } from '../../../query/index.js';\nimport type { TranslatedQuery, ProviderName } from '../../../providers/base/types.js';\nimport { translateQuery as translatePubmed } from '../../../providers/pubmed/translator.js';\nimport { translateQuery as translateEric } from '../../../providers/eric/translator.js';\nimport { translateQuery as translateArxiv } from '../../../providers/arxiv/translator.js';\nimport { translateQuery as translateScopus } from '../../../providers/scopus/translator.js';\n\n/**\n * Available translators by provider name.\n */\nconst translators: Record<\n string,\n (ast: Parameters<typeof translatePubmed>[0]) => TranslatedQuery\n> = {\n pubmed: translatePubmed,\n eric: translateEric,\n arxiv: translateArxiv,\n scopus: translateScopus,\n};\n\n/**\n * Default providers to translate for.\n */\nconst DEFAULT_PROVIDERS: ProviderName[] = ['pubmed', 'eric', 'arxiv', 'scopus'];\n\n/**\n * Options for translate command.\n */\nexport interface TranslateOptions {\n /** Specific providers to translate for */\n providers?: ProviderName[];\n}\n\n/**\n * Result of query translation.\n */\nexport interface TranslateResult {\n /** Whether translation succeeded */\n success: boolean;\n /** Error message if failed */\n error?: string;\n /** Translations by provider name */\n translations?: Record<string, TranslatedQuery>;\n}\n\n/**\n * Translate a query YAML file to native syntax for each provider.\n *\n * @param filePath - Path to the query file\n * @param options - Translation options\n * @returns Translation result\n */\nexport async function translateQueryCommand(\n filePath: string,\n options: TranslateOptions = {}\n): Promise<TranslateResult> {\n // Read file\n let content: string;\n try {\n content = await readFile(filePath, 'utf-8');\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Failed to read file';\n return {\n success: false,\n error: message,\n };\n }\n\n // Parse and validate\n let ast;\n try {\n ast = parseQueryString(content);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Failed to parse query file';\n return {\n success: false,\n error: message,\n };\n }\n\n // Determine which providers to translate for\n const providers = options.providers ?? DEFAULT_PROVIDERS;\n\n // Translate for each provider\n const translations: Record<string, TranslatedQuery> = {};\n\n for (const provider of providers) {\n const translator = translators[provider];\n if (translator) {\n try {\n translations[provider] = translator(ast);\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : `Failed to translate for ${provider}`;\n return {\n success: false,\n error: `${provider}: ${message}`,\n };\n }\n }\n }\n\n return {\n success: true,\n translations,\n };\n}\n\n/**\n * Format translation result for display.\n */\nexport function formatTranslateResult(\n result: TranslateResult,\n filePath: string\n): string {\n if (!result.success) {\n return `✗ Failed to translate: ${filePath}\\n Error: ${result.error}`;\n }\n\n const lines = [`Translations for: ${filePath}`, ''];\n\n if (result.translations) {\n for (const [provider, translation] of Object.entries(result.translations)) {\n lines.push(`[${provider.toUpperCase()}]`);\n lines.push(translation.native);\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n}\n"],"names":["translatePubmed","translateEric","translateArxiv","translateScopus"],"mappings":";;;;;;;AAgBA,MAAM,cAGF;AAAA,EACF,QAAQA;AAAAA,EACR,MAAMC;AAAAA,EACN,OAAOC;AAAAA,EACP,QAAQC;AACV;AAKA,MAAM,oBAAoC,CAAC,UAAU,QAAQ,SAAS,QAAQ;AA6B9E,eAAsB,sBACpB,UACA,UAA4B,IACF;AAE1B,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,SAAS,UAAU,OAAO;AAAA,EAC5C,SAAS,OAAO;AACd,UAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IAAA;AAAA,EAEX;AAGA,MAAI;AACJ,MAAI;AACF,UAAM,iBAAiB,OAAO;AAAA,EAChC,SAAS,OAAO;AACd,UAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IAAA;AAAA,EAEX;AAGA,QAAM,YAAY,QAAQ,aAAa;AAGvC,QAAM,eAAgD,CAAA;AAEtD,aAAW,YAAY,WAAW;AAChC,UAAM,aAAa,YAAY,QAAQ;AACvC,QAAI,YAAY;AACd,UAAI;AACF,qBAAa,QAAQ,IAAI,WAAW,GAAG;AAAA,MACzC,SAAS,OAAO;AACd,cAAM,UACJ,iBAAiB,QACb,MAAM,UACN,2BAA2B,QAAQ;AACzC,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,GAAG,QAAQ,KAAK,OAAO;AAAA,QAAA;AAAA,MAElC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,EAAA;AAEJ;AAKO,SAAS,sBACd,QACA,UACQ;AACR,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,0BAA0B,QAAQ;AAAA,WAAc,OAAO,KAAK;AAAA,EACrE;AAEA,QAAM,QAAQ,CAAC,qBAAqB,QAAQ,IAAI,EAAE;AAElD,MAAI,OAAO,cAAc;AACvB,eAAW,CAAC,UAAU,WAAW,KAAK,OAAO,QAAQ,OAAO,YAAY,GAAG;AACzE,YAAM,KAAK,IAAI,SAAS,YAAA,CAAa,GAAG;AACxC,YAAM,KAAK,YAAY,MAAM;AAC7B,YAAM,KAAK,EAAE;AAAA,IACf;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;"}
|
|
1
|
+
{"version":3,"file":"translate.js","sources":["../../../../src/cli/commands/query/translate.ts"],"sourcesContent":["/**\n * Query translate command implementation.\n *\n * Translates a YAML query file to native database query syntax for each provider.\n */\nimport { readFile } from 'node:fs/promises';\nimport { parseQueryString } from '../../../query/index.js';\nimport type { TranslatedQuery, ProviderName } from '../../../providers/base/types.js';\nimport { translateQuery as translatePubmed } from '../../../providers/pubmed/translator.js';\nimport { translateQuery as translateEric } from '../../../providers/eric/translator.js';\nimport { translateQuery as translateArxiv } from '../../../providers/arxiv/translator.js';\nimport { translateQuery as translateScopus } from '../../../providers/scopus/translator.js';\n\n/**\n * Available translators by provider name.\n */\nconst translators: Record<\n string,\n (ast: Parameters<typeof translatePubmed>[0]) => TranslatedQuery\n> = {\n pubmed: translatePubmed,\n eric: translateEric,\n arxiv: translateArxiv,\n scopus: translateScopus,\n};\n\n/**\n * Default providers to translate for.\n */\nconst DEFAULT_PROVIDERS: ProviderName[] = ['pubmed', 'eric', 'arxiv', 'scopus'];\n\n/**\n * Options for translate command.\n */\nexport interface TranslateOptions {\n /** Specific providers to translate for */\n providers?: ProviderName[];\n}\n\n/**\n * Result of query translation.\n */\nexport interface TranslateResult {\n /** Whether translation succeeded */\n success: boolean;\n /** Error message if failed */\n error?: string;\n /** Translations by provider name */\n translations?: Record<string, TranslatedQuery>;\n}\n\n/**\n * Translate a query YAML file to native syntax for each provider.\n *\n * @param filePath - Path to the query file\n * @param options - Translation options\n * @returns Translation result\n */\nexport async function translateQueryCommand(\n filePath: string,\n options: TranslateOptions = {}\n): Promise<TranslateResult> {\n // Read file\n let content: string;\n try {\n content = await readFile(filePath, 'utf-8');\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Failed to read file';\n return {\n success: false,\n error: message,\n };\n }\n\n // Parse and validate\n let ast;\n try {\n ast = parseQueryString(content);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Failed to parse query file';\n return {\n success: false,\n error: message,\n };\n }\n\n // Determine which providers to translate for\n const providers = options.providers ?? DEFAULT_PROVIDERS;\n\n // Translate for each provider\n const translations: Record<string, TranslatedQuery> = {};\n\n for (const provider of providers) {\n const translator = translators[provider];\n if (translator) {\n try {\n translations[provider] = translator(ast);\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : `Failed to translate for ${provider}`;\n return {\n success: false,\n error: `${provider}: ${message}`,\n };\n }\n }\n }\n\n return {\n success: true,\n translations,\n };\n}\n\n/**\n * Format translation result for display.\n */\nexport function formatTranslateResult(\n result: TranslateResult,\n filePath: string\n): string {\n if (!result.success) {\n return `✗ Failed to translate: ${filePath}\\n Error: ${result.error}`;\n }\n\n const lines = [`Translations for: ${filePath}`, ''];\n\n if (result.translations) {\n for (const [provider, translation] of Object.entries(result.translations)) {\n lines.push(`[${provider.toUpperCase()}]`);\n lines.push(translation.native);\n if (translation.warnings && translation.warnings.length > 0) {\n for (const warning of translation.warnings) {\n lines.push(`⚠ ${warning}`);\n }\n }\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n}\n"],"names":["translatePubmed","translateEric","translateArxiv","translateScopus"],"mappings":";;;;;;;AAgBA,MAAM,cAGF;AAAA,EACF,QAAQA;AAAAA,EACR,MAAMC;AAAAA,EACN,OAAOC;AAAAA,EACP,QAAQC;AACV;AAKA,MAAM,oBAAoC,CAAC,UAAU,QAAQ,SAAS,QAAQ;AA6B9E,eAAsB,sBACpB,UACA,UAA4B,IACF;AAE1B,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,SAAS,UAAU,OAAO;AAAA,EAC5C,SAAS,OAAO;AACd,UAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IAAA;AAAA,EAEX;AAGA,MAAI;AACJ,MAAI;AACF,UAAM,iBAAiB,OAAO;AAAA,EAChC,SAAS,OAAO;AACd,UAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IAAA;AAAA,EAEX;AAGA,QAAM,YAAY,QAAQ,aAAa;AAGvC,QAAM,eAAgD,CAAA;AAEtD,aAAW,YAAY,WAAW;AAChC,UAAM,aAAa,YAAY,QAAQ;AACvC,QAAI,YAAY;AACd,UAAI;AACF,qBAAa,QAAQ,IAAI,WAAW,GAAG;AAAA,MACzC,SAAS,OAAO;AACd,cAAM,UACJ,iBAAiB,QACb,MAAM,UACN,2BAA2B,QAAQ;AACzC,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,GAAG,QAAQ,KAAK,OAAO;AAAA,QAAA;AAAA,MAElC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,EAAA;AAEJ;AAKO,SAAS,sBACd,QACA,UACQ;AACR,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,0BAA0B,QAAQ;AAAA,WAAc,OAAO,KAAK;AAAA,EACrE;AAEA,QAAM,QAAQ,CAAC,qBAAqB,QAAQ,IAAI,EAAE;AAElD,MAAI,OAAO,cAAc;AACvB,eAAW,CAAC,UAAU,WAAW,KAAK,OAAO,QAAQ,OAAO,YAAY,GAAG;AACzE,YAAM,KAAK,IAAI,SAAS,YAAA,CAAa,GAAG;AACxC,YAAM,KAAK,YAAY,MAAM;AAC7B,UAAI,YAAY,YAAY,YAAY,SAAS,SAAS,GAAG;AAC3D,mBAAW,WAAW,YAAY,UAAU;AAC1C,gBAAM,KAAK,KAAK,OAAO,EAAE;AAAA,QAC3B;AAAA,MACF;AACA,YAAM,KAAK,EAAE;AAAA,IACf;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { MeSHLookupClient } from '../../../query/mesh-lookup.js';
|
|
2
|
+
import { CountVocabValidator, VocabValidationResult } from '../../../query/vocab-validator.js';
|
|
1
3
|
/**
|
|
2
4
|
* Result of query validation.
|
|
3
5
|
*/
|
|
@@ -10,6 +12,8 @@ export interface ValidateResult {
|
|
|
10
12
|
queryName?: string;
|
|
11
13
|
/** Number of query blocks (if valid) */
|
|
12
14
|
blockCount?: number;
|
|
15
|
+
/** Controlled vocabulary validation results (auto-checked by default) */
|
|
16
|
+
vocabResult?: VocabValidationResult;
|
|
13
17
|
}
|
|
14
18
|
/**
|
|
15
19
|
* Validate a query YAML file.
|
|
@@ -17,9 +21,26 @@ export interface ValidateResult {
|
|
|
17
21
|
* @param filePath - Path to the query file
|
|
18
22
|
* @returns Validation result
|
|
19
23
|
*/
|
|
20
|
-
export declare function validateQueryCommand(filePath: string
|
|
24
|
+
export declare function validateQueryCommand(filePath: string, options?: {
|
|
25
|
+
meshClient?: MeSHLookupClient;
|
|
26
|
+
noVocab?: boolean;
|
|
27
|
+
countValidators?: CountVocabValidator[];
|
|
28
|
+
}): Promise<ValidateResult>;
|
|
21
29
|
/**
|
|
22
30
|
* Format validation result for display.
|
|
23
31
|
*/
|
|
24
32
|
export declare function formatValidateResult(result: ValidateResult, filePath: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Check if a validation result contains invalid controlled vocabulary terms.
|
|
35
|
+
*/
|
|
36
|
+
export declare function hasVocabErrors(result: ValidateResult): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Detect whether a YAML file has a yaml-language-server $schema comment
|
|
39
|
+
* in its first 5 lines.
|
|
40
|
+
*/
|
|
41
|
+
export declare function detectSchemaLink(filePath: string): Promise<boolean>;
|
|
42
|
+
/**
|
|
43
|
+
* Format controlled vocabulary validation results for display.
|
|
44
|
+
*/
|
|
45
|
+
export declare function formatVocabValidationOutput(result: VocabValidationResult): string;
|
|
25
46
|
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/query/validate.ts"],"names":[],"mappings":"AASA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/query/validate.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC3B,MAAM,mCAAmC,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAyCD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IACR,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACzC,GACA,OAAO,CAAC,cAAc,CAAC,CA0BzB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,MAAM,GACf,MAAM,CAiBR;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAE9D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQzE;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,qBAAqB,GAC5B,MAAM,CA6BR"}
|
|
@@ -1,49 +1,56 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { parseQueryString } from "../../../query/parser.js";
|
|
3
3
|
import { ValidationError } from "../../../query/validator.js";
|
|
4
|
+
import { extractControlledVocabTerms, validateControlledVocab } from "../../../query/vocab-validator.js";
|
|
4
5
|
import { ZodError } from "zod";
|
|
5
|
-
async function
|
|
6
|
+
async function parseQueryFile(filePath) {
|
|
6
7
|
let content;
|
|
7
8
|
try {
|
|
8
9
|
content = await readFile(filePath, "utf-8");
|
|
9
10
|
} catch (error) {
|
|
10
11
|
const message = error instanceof Error ? error.message : "Failed to read file";
|
|
11
|
-
return {
|
|
12
|
-
success: false,
|
|
13
|
-
errors: [message]
|
|
14
|
-
};
|
|
12
|
+
return { result: { success: false, errors: [message] } };
|
|
15
13
|
}
|
|
16
14
|
try {
|
|
17
15
|
const ast = parseQueryString(content);
|
|
18
|
-
return {
|
|
19
|
-
success: true,
|
|
20
|
-
queryName: ast.name,
|
|
21
|
-
blockCount: ast.blocks.length
|
|
22
|
-
};
|
|
16
|
+
return { ast };
|
|
23
17
|
} catch (error) {
|
|
24
18
|
if (error instanceof ZodError) {
|
|
25
19
|
const errors = error.issues.map((e) => {
|
|
26
20
|
const path = e.path.join(".");
|
|
27
21
|
return path ? `${path}: ${e.message}` : e.message;
|
|
28
22
|
});
|
|
29
|
-
return {
|
|
30
|
-
success: false,
|
|
31
|
-
errors
|
|
32
|
-
};
|
|
23
|
+
return { result: { success: false, errors } };
|
|
33
24
|
}
|
|
34
25
|
if (error instanceof ValidationError) {
|
|
35
|
-
return {
|
|
36
|
-
success: false,
|
|
37
|
-
errors: [error.message]
|
|
38
|
-
};
|
|
26
|
+
return { result: { success: false, errors: [error.message] } };
|
|
39
27
|
}
|
|
40
28
|
const message = error instanceof Error ? error.message : "Unknown validation error";
|
|
41
|
-
return {
|
|
42
|
-
success: false,
|
|
43
|
-
errors: [message]
|
|
44
|
-
};
|
|
29
|
+
return { result: { success: false, errors: [message] } };
|
|
45
30
|
}
|
|
46
31
|
}
|
|
32
|
+
async function validateQueryCommand(filePath, options) {
|
|
33
|
+
const parsed = await parseQueryFile(filePath);
|
|
34
|
+
if ("result" in parsed) {
|
|
35
|
+
return parsed.result;
|
|
36
|
+
}
|
|
37
|
+
const result = {
|
|
38
|
+
success: true,
|
|
39
|
+
queryName: parsed.ast.name,
|
|
40
|
+
blockCount: parsed.ast.blocks.length
|
|
41
|
+
};
|
|
42
|
+
if (options?.meshClient && !options.noVocab) {
|
|
43
|
+
const terms = extractControlledVocabTerms(parsed.ast);
|
|
44
|
+
if (terms.length > 0) {
|
|
45
|
+
result.vocabResult = await validateControlledVocab(
|
|
46
|
+
parsed.ast,
|
|
47
|
+
options.meshClient,
|
|
48
|
+
options.countValidators ? { countValidators: options.countValidators } : void 0
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
47
54
|
function formatValidateResult(result, filePath) {
|
|
48
55
|
if (result.success) {
|
|
49
56
|
const lines2 = [
|
|
@@ -61,8 +68,44 @@ function formatValidateResult(result, filePath) {
|
|
|
61
68
|
}
|
|
62
69
|
return lines.join("\n");
|
|
63
70
|
}
|
|
71
|
+
function hasVocabErrors(result) {
|
|
72
|
+
return (result.vocabResult?.invalid.length ?? 0) > 0;
|
|
73
|
+
}
|
|
74
|
+
async function detectSchemaLink(filePath) {
|
|
75
|
+
try {
|
|
76
|
+
const content = await readFile(filePath, "utf-8");
|
|
77
|
+
const lines = content.split("\n").slice(0, 5);
|
|
78
|
+
return lines.some((line) => /yaml-language-server.*\$schema=/.test(line));
|
|
79
|
+
} catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function formatVocabValidationOutput(result) {
|
|
84
|
+
if (result.valid.length === 0 && result.invalid.length === 0 && result.errors.length === 0) {
|
|
85
|
+
return "";
|
|
86
|
+
}
|
|
87
|
+
const lines = ["", "Controlled vocabulary:"];
|
|
88
|
+
for (const item of result.valid) {
|
|
89
|
+
lines.push(` ✓ ${item.vocabulary}: "${item.term}"`);
|
|
90
|
+
}
|
|
91
|
+
for (const item of result.invalid) {
|
|
92
|
+
lines.push(` ✗ ${item.vocabulary}: "${item.term}" — not found`);
|
|
93
|
+
if (item.suggestions && item.suggestions.length > 0) {
|
|
94
|
+
lines.push(
|
|
95
|
+
` Did you mean: ${item.suggestions.map((s) => `"${s}"`).join(", ")}`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
for (const item of result.errors) {
|
|
100
|
+
lines.push(` ⚠ ${item.vocabulary}: "${item.term}" — ${item.error}`);
|
|
101
|
+
}
|
|
102
|
+
return lines.join("\n");
|
|
103
|
+
}
|
|
64
104
|
export {
|
|
105
|
+
detectSchemaLink,
|
|
65
106
|
formatValidateResult,
|
|
107
|
+
formatVocabValidationOutput,
|
|
108
|
+
hasVocabErrors,
|
|
66
109
|
validateQueryCommand
|
|
67
110
|
};
|
|
68
111
|
//# sourceMappingURL=validate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sources":["../../../../src/cli/commands/query/validate.ts"],"sourcesContent":["/**\n * Query validate command implementation.\n *\n * Validates a YAML query file and reports any errors.\n */\nimport { readFile } from 'node:fs/promises';\nimport { parseQueryString, ValidationError } from '../../../query/index.js';\nimport { ZodError } from 'zod';\n\n/**\n * Result of query validation.\n */\nexport interface ValidateResult {\n /** Whether validation succeeded */\n success: boolean;\n /** Error messages if validation failed */\n errors?: string[];\n /** Query name (if valid) */\n queryName?: string;\n /** Number of query blocks (if valid) */\n blockCount?: number;\n}\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"validate.js","sources":["../../../../src/cli/commands/query/validate.ts"],"sourcesContent":["/**\n * Query validate command implementation.\n *\n * Validates a YAML query file and reports any errors.\n * Optionally validates controlled vocabulary terms (MeSH, ERIC, Emtree) against external APIs.\n */\nimport { readFile } from 'node:fs/promises';\nimport { parseQueryString, ValidationError } from '../../../query/index.js';\nimport { ZodError } from 'zod';\nimport type { MeSHLookupClient } from '../../../query/mesh-lookup.js';\nimport type { QueryAST } from '../../../query/types.js';\nimport {\n extractControlledVocabTerms,\n validateControlledVocab,\n type CountVocabValidator,\n type VocabValidationResult,\n} from '../../../query/vocab-validator.js';\n\n/**\n * Result of query validation.\n */\nexport interface ValidateResult {\n /** Whether validation succeeded */\n success: boolean;\n /** Error messages if validation failed */\n errors?: string[];\n /** Query name (if valid) */\n queryName?: string;\n /** Number of query blocks (if valid) */\n blockCount?: number;\n /** Controlled vocabulary validation results (auto-checked by default) */\n vocabResult?: VocabValidationResult;\n}\n\n/**\n * Read and parse a query YAML file.\n *\n * @returns The parsed AST on success, or a ValidateResult with errors on failure.\n */\nasync function parseQueryFile(\n filePath: string\n): Promise<{ ast: QueryAST } | { result: ValidateResult }> {\n let content: string;\n try {\n content = await readFile(filePath, 'utf-8');\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Failed to read file';\n return { result: { success: false, errors: [message] } };\n }\n\n try {\n const ast = parseQueryString(content);\n return { ast };\n } catch (error) {\n if (error instanceof ZodError) {\n const errors = error.issues.map((e) => {\n const path = e.path.join('.');\n return path ? `${path}: ${e.message}` : e.message;\n });\n return { result: { success: false, errors } };\n }\n\n if (error instanceof ValidationError) {\n return { result: { success: false, errors: [error.message] } };\n }\n\n const message =\n error instanceof Error ? error.message : 'Unknown validation error';\n return { result: { success: false, errors: [message] } };\n }\n}\n\n/**\n * Validate a query YAML file.\n *\n * @param filePath - Path to the query file\n * @returns Validation result\n */\nexport async function validateQueryCommand(\n filePath: string,\n options?: {\n meshClient?: MeSHLookupClient;\n noVocab?: boolean;\n countValidators?: CountVocabValidator[];\n }\n): Promise<ValidateResult> {\n const parsed = await parseQueryFile(filePath);\n\n if ('result' in parsed) {\n return parsed.result;\n }\n\n const result: ValidateResult = {\n success: true,\n queryName: parsed.ast.name,\n blockCount: parsed.ast.blocks.length,\n };\n\n // Auto-validate vocab when controlled vocab terms exist\n if (options?.meshClient && !options.noVocab) {\n const terms = extractControlledVocabTerms(parsed.ast);\n if (terms.length > 0) {\n result.vocabResult = await validateControlledVocab(\n parsed.ast,\n options.meshClient,\n options.countValidators ? { countValidators: options.countValidators } : undefined\n );\n }\n }\n\n return result;\n}\n\n/**\n * Format validation result for display.\n */\nexport function formatValidateResult(\n result: ValidateResult,\n filePath: string\n): string {\n if (result.success) {\n const lines = [\n `✓ Valid query file: ${filePath}`,\n ` Name: ${result.queryName}`,\n ` Blocks: ${result.blockCount}`,\n ];\n return lines.join('\\n');\n }\n\n const lines = [`✗ Invalid query file: ${filePath}`, '', 'Errors:'];\n if (result.errors) {\n for (const error of result.errors) {\n lines.push(` - ${error}`);\n }\n }\n return lines.join('\\n');\n}\n\n/**\n * Check if a validation result contains invalid controlled vocabulary terms.\n */\nexport function hasVocabErrors(result: ValidateResult): boolean {\n return (result.vocabResult?.invalid.length ?? 0) > 0;\n}\n\n/**\n * Detect whether a YAML file has a yaml-language-server $schema comment\n * in its first 5 lines.\n */\nexport async function detectSchemaLink(filePath: string): Promise<boolean> {\n try {\n const content = await readFile(filePath, 'utf-8');\n const lines = content.split('\\n').slice(0, 5);\n return lines.some((line) => /yaml-language-server.*\\$schema=/.test(line));\n } catch {\n return false;\n }\n}\n\n/**\n * Format controlled vocabulary validation results for display.\n */\nexport function formatVocabValidationOutput(\n result: VocabValidationResult\n): string {\n if (\n result.valid.length === 0 &&\n result.invalid.length === 0 &&\n result.errors.length === 0\n ) {\n return '';\n }\n\n const lines: string[] = ['', 'Controlled vocabulary:'];\n\n for (const item of result.valid) {\n lines.push(` ✓ ${item.vocabulary}: \"${item.term}\"`);\n }\n\n for (const item of result.invalid) {\n lines.push(` ✗ ${item.vocabulary}: \"${item.term}\" — not found`);\n if (item.suggestions && item.suggestions.length > 0) {\n lines.push(\n ` Did you mean: ${item.suggestions.map((s) => `\"${s}\"`).join(', ')}`\n );\n }\n }\n\n for (const item of result.errors) {\n lines.push(` ⚠ ${item.vocabulary}: \"${item.term}\" — ${item.error}`);\n }\n\n return lines.join('\\n');\n}\n"],"names":["lines"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/review/extract.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAsD,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAErH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9D,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAGD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAgLD;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAU/C;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,oBAAoB,EAC7B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,mBAAmB,CAAC,
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/review/extract.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAsD,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAErH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9D,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAGD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAgLD;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAU/C;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,oBAAoB,EAC7B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,mBAAmB,CAAC,CAsG9B"}
|
|
@@ -190,8 +190,7 @@ async function executeReviewExtract(options, sessionsDir) {
|
|
|
190
190
|
const outputDir = dirname(outputPath);
|
|
191
191
|
await mkdir(outputDir, { recursive: true });
|
|
192
192
|
await writeFile(outputPath, finalContent, "utf-8");
|
|
193
|
-
const
|
|
194
|
-
const schemaSourcePath = join(schemasDir, "review.schema.json");
|
|
193
|
+
const schemaSourcePath = join(sessionDir, ".internal", "review.schema.json");
|
|
195
194
|
const schemaDestPath = join(outputDir, "review.schema.json");
|
|
196
195
|
try {
|
|
197
196
|
await access(schemaSourcePath);
|