├── .gitignore ├── README.md ├── src ├── config.json ├── test.ts └── index.ts ├── .vscode ├── settings.json └── launch.json ├── package.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | out 3 | doc/template/3d-examples/bin-debug 4 | /out-builder 5 | dist 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ExtractCode 2 | 软著代码提取 3 | 配置导出规则,删除空行和注释,直接导出符合软著申请要求的word文档 4 | ## Install 5 | 修改你的配置文件src/config.json 6 | ``` 7 | $ npm install 8 | $ npm run ext 9 | 10 | ``` 11 | 12 | ## 其他 13 | 暂不支持页码的添加,需要手动编辑导出的文档 14 | -------------------------------------------------------------------------------- /src/config.json: -------------------------------------------------------------------------------- 1 | //路劲分割请使用'/' 2 | { 3 | "project": "C:/Users/liyang/Desktop/repo/editor/paper", //项目目录 4 | "globs": ["src/**/*.ts", "src/**/*.tsx"], //规则 5 | "excludeFileName": [], //按照文件名排除文件 6 | "excludeFilePath": [], //按照文件路径排除文件 7 | "excludeLineText": [], //按照包含的内容排除行 8 | "headerText": "XXXX 源代码V1.0", //页眉 9 | "fontFace": "Arial", //字体 10 | "fontSize": 10, //字号 11 | "lineCount": 3101 //导出代码总行数 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.json": "jsonc" // JSON文件中可以有注释 4 | }, 5 | "[javascript]": { 6 | "editor.defaultFormatter": "vscode.typescript-language-features" 7 | }, 8 | "[typescript]": { 9 | "editor.defaultFormatter": "vscode.typescript-language-features" 10 | }, 11 | "files.eol": "\n", 12 | "editor.tabSize": 4, 13 | "editor.formatOnSave": true, 14 | "editor.defaultFormatter": "esbenp.prettier-vscode", 15 | "typescript.tsdk": "node_modules/typescript/lib" 16 | } 17 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "skipFiles": [ 12 | "/**" 13 | ], 14 | "program": "${workspaceFolder}\\dist\\index.js" 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "extractcode", 3 | "version": "1.0.0", 4 | "description": "软著代码提取", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "start": "tsc -w", 9 | "ext": "tsc && node dist/index.js", 10 | "test": "tsc && mocha dist/test.js", 11 | "eslint": "eslint src --ext .ts" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@microsoft/node-core-library": "~3.14.0", 17 | "@types/mocha": "^5.2.7", 18 | "@types/strip-json-comments": "^3.0.0", 19 | "args": "~5.0.1", 20 | "compressing": "~1.4.0", 21 | "mocha": "^6.2.0", 22 | "node-pandoc": "^0.3.0", 23 | "officegen": "^0.6.3", 24 | "strip-json-comments": "^3.0.1", 25 | "walk": "~2.3.14", 26 | "walk-sync": "^2.0.2" 27 | }, 28 | "devDependencies": { 29 | "@types/args": "~3.0.0", 30 | "@types/node": "~12.7.2", 31 | "@types/walk": "~2.3.0", 32 | "@typescript-eslint/eslint-plugin": "^2.24.0", 33 | "@typescript-eslint/parser": "^2.24.0", 34 | "eslint": "^6.8.0", 35 | "prettier": "^1.19.1", 36 | "typescript": "^3.5.3" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import * as main from './index'; 3 | describe('main', function () { 4 | describe('#filterLines()', function () { 5 | it('', () => { 6 | const excludeLine = ['import ']; 7 | const src = [ 8 | `import * as fs from 'fs-extra';`, 9 | `const officegen = require('officegen');`, 10 | `import walk from 'walk-sync';` 11 | ]; 12 | const result = main.filterLines(src, excludeLine); 13 | assert.equal(result[0], `const officegen = require('officegen');`); 14 | }); 15 | }); 16 | describe('#filterFileName()', function () { 17 | it('', () => { 18 | const excludeLine = ['a.ts', 'b.ts']; 19 | const src = [ 20 | `C:/Users/pc/project/a.ts`, 21 | `C:/Users/pc/project/b.ts`, 22 | `C:/Users/pc/project/c.ts` 23 | ]; 24 | const result = main.filterFileName(src, excludeLine); 25 | assert.equal(result[0], `C:/Users/pc/project/c.ts`); 26 | }); 27 | }); 28 | describe('#filterFilePath()', function () { 29 | it('', () => { 30 | const excludeLine = ['C:/Users/pc/project/a.ts', 'C:/Users/pc/project/b.ts', 'C:/Users/pc/project/d']; 31 | const src = [ 32 | `C:/Users/pc/project/a.ts`, 33 | `C:/Users/pc/project/b.ts`, 34 | `C:/Users/pc/project/c.ts`, 35 | `C:/Users/pc/project/d/d.ts`, 36 | ]; 37 | const result = main.filterFilePath(src, excludeLine); 38 | assert.equal(result[0], `C:/Users/pc/project/c.ts`); 39 | }); 40 | }); 41 | }); -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs-extra'; 2 | import * as path from 'path'; 3 | import walk from 'walk-sync'; 4 | import stripJsonComments from 'strip-json-comments'; 5 | const officegen = require('officegen'); 6 | const config = JSON.parse(stripJsonComments(fs.readFileSync('src/config.json', 'utf-8'))); 7 | 8 | 9 | const root = config.project;//提取路径 10 | const globs = config.globs;//提取范围 11 | const temp = 'out/temp.txt'; 12 | const excludeFileName: string[] = config.excludeFileName;//排除的文件,文件名 13 | const excludeFilePath: string[] = config.excludeFilePath;//排除的行,字符串包含 14 | const excludeLineText: string[] = config.excludeLineText;//排除的行,字符串包含 15 | const headerText = config.headerText; 16 | const fontFace = config.fontFace; 17 | const fontSize = config.fontSize; 18 | async function run() { 19 | if (!fs.existsSync(root)) { 20 | console.error("project not exist"); 21 | return; 22 | }; 23 | let paths = await getAllFiles(root, globs); 24 | paths = filterFileName(paths, excludeFileName); 25 | paths = filterFilePath(paths, excludeFilePath); 26 | fs.removeSync(temp); 27 | fs.ensureFileSync(temp); 28 | let lines: string[] = []; 29 | for (const e of paths) { 30 | const ct = formatFile2Content(e); 31 | lines = lines.concat(filterLines(ct.split('\n'), excludeLineText)); 32 | fs.appendFileSync(temp, ct); 33 | 34 | } 35 | const r1 = lines.slice(0, 3101).join('\n'); 36 | genDoc(r1); 37 | } 38 | ///按特征文字过滤行数据 39 | export function filterLines(src: string[], ext: string[]) { 40 | return src.filter((e) => ext.every((ee) => !e.includes(ee))); 41 | } 42 | ///按文件名排除 43 | export function filterFileName(paths: string[], exc: string[]) { 44 | return paths.filter((e) => exc.indexOf(path.basename(e)) === -1); 45 | } 46 | ///按文件路径排除 47 | export function filterFilePath(paths: string[], excs: string[]) { 48 | return paths.filter((e) => { 49 | const excsMatch = excs.filter((exc) => { 50 | return e.indexOf(exc) === 0; 51 | }); 52 | return excsMatch.length === 0; 53 | }); 54 | } 55 | ///获取文件列表 56 | async function getAllFiles(root: string, globs: string[]) { 57 | const paths = walk(root, { globs: globs }).map((e) => path.join(root, e)).map((e) => e.split(path.sep).join('/')); 58 | return paths; 59 | } 60 | ///读取文件并返回过滤空行和注释的内容 61 | function formatFile2Content(path: string) { 62 | let content = fs.readFileSync(path, 'utf-8'); 63 | content = replaceNote(content); 64 | content = replaceBlank(content); 65 | return content; 66 | } 67 | function replaceBlank(src: string) { 68 | const reg = /\n(\n)*( )*(\n)*\n/g; 69 | return src.replace(/(\n[\s\t]*\r*\n)/g, '\n').replace(/^[\n\r\n\t]*|[\n\r\n\t]*$/g, '');//src.replace(reg,''); 70 | } 71 | function replaceNote(src: string) { 72 | const reg = /(\/\/.*)|(\/\*[\s\S]*?\*\/)/g; 73 | return src.replace(reg, ''); 74 | } 75 | ///生成doc 76 | function genDoc(src: string) { 77 | const docx = officegen({ 78 | type: 'docx' 79 | }); 80 | docx.on('finalize', function (written: any) { 81 | console.log( 82 | 'Finish to create a Microsoft Word document.' 83 | ); 84 | }); 85 | docx.on('error', function (err: any) { 86 | console.log(err); 87 | }); 88 | const pObj = docx.createP(); 89 | pObj.addText(src, { font_face: fontFace, font_size: fontSize }); 90 | 91 | const header = docx.getHeader().createP(); 92 | header.addText(headerText); 93 | //TODO:页眉加入页码 94 | header.options.align = 'left'; 95 | const out = fs.createWriteStream('out/out.docx'); 96 | docx.generate(out); 97 | } 98 | run().catch((e) => { 99 | console.log(e); 100 | }); 101 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | // "incremental": true, /* Enable incremental compilation */ 5 | "target": "es5", 6 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 7 | "module": "commonjs", 8 | /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 9 | "lib": [ 10 | "es2015" 11 | ], 12 | "skipLibCheck": true, 13 | /* Specify library files to be included in the compilation. */ 14 | // "allowJs": true, /* Allow javascript files to be compiled. */ 15 | // "checkJs": true, /* Report errors in .js files. */ 16 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 17 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 18 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 19 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 20 | // "outFile": "./", /* Concatenate and emit output to single file. */ 21 | "outDir": "./dist", 22 | /* Redirect output structure to the directory. */ 23 | "rootDir": "./src", 24 | /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 25 | // "composite": true, /* Enable project compilation */ 26 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 27 | // "removeComments": true, /* Do not emit comments to output. */ 28 | // "noEmit": true, /* Do not emit outputs. */ 29 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 30 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 31 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 32 | /* Strict Type-Checking Options */ 33 | "strict": true, 34 | /* Enable all strict type-checking options. */ 35 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 36 | // "strictNullChecks": true, /* Enable strict null checks. */ 37 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 38 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 39 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 40 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 41 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 42 | /* Additional Checks */ 43 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 44 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 45 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 46 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 47 | /* Module Resolution Options */ 48 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 49 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 50 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 51 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 52 | // "typeRoots": [], /* List of folders to include type definitions from. */ 53 | // "types": [], /* Type declaration files to be included in compilation. */ 54 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 55 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 56 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 57 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 58 | /* Source Map Options */ 59 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 60 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 61 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 62 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 63 | /* Experimental Options */ 64 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 65 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 66 | }, 67 | "include": [ 68 | "src" 69 | ] 70 | } --------------------------------------------------------------------------------