@liuhange/dsh-construction-data-inventory 0.0.0-stage → 3.1.1

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.
Files changed (54) hide show
  1. package/README.md +72 -3
  2. package/config/classification-config.json +111 -0
  3. package/config/encoding-rule-config.json +9 -0
  4. package/config/source-adapter-config.json +26 -0
  5. package/cordis.patch.yml +9 -0
  6. package/lib/acceptance-doc-adapter.js +56 -0
  7. package/lib/asset-code-generator.js +82 -0
  8. package/lib/asset-ledger-exporter.js +35 -0
  9. package/lib/change-traceability-checker.js +79 -0
  10. package/lib/checksum-calculator.js +53 -0
  11. package/lib/classification-mapper.js +50 -0
  12. package/lib/code-uniqueness-validator.js +20 -0
  13. package/lib/construction-config-loader.js +105 -0
  14. package/lib/contract-adapter.js +57 -0
  15. package/lib/default-classification-config.js +112 -0
  16. package/lib/default-encoding-rule-config.js +10 -0
  17. package/lib/ifc-model-adapter.js +156 -0
  18. package/lib/index.js +304 -0
  19. package/lib/input-validator.js +113 -0
  20. package/lib/invariant.js +32 -0
  21. package/lib/inventory-report-generator.js +140 -0
  22. package/lib/policy-basis-builder.js +25 -0
  23. package/lib/progress-record-adapter.js +58 -0
  24. package/lib/report-desensitizer.js +72 -0
  25. package/lib/review-override-recorder.js +54 -0
  26. package/lib/sequential-code-allocator.js +22 -0
  27. package/lib/source-adapter.js +2 -0
  28. package/lib/types/acceptance-doc-adapter.d.ts +11 -0
  29. package/lib/types/asset-code-generator.d.ts +17 -0
  30. package/lib/types/asset-ledger-exporter.d.ts +7 -0
  31. package/lib/types/change-traceability-checker.d.ts +11 -0
  32. package/lib/types/checksum-calculator.d.ts +7 -0
  33. package/lib/types/classification-mapper.d.ts +12 -0
  34. package/lib/types/code-uniqueness-validator.d.ts +8 -0
  35. package/lib/types/construction-config-loader.d.ts +11 -0
  36. package/lib/types/contract-adapter.d.ts +11 -0
  37. package/lib/types/default-classification-config.d.ts +3 -0
  38. package/lib/types/default-encoding-rule-config.d.ts +3 -0
  39. package/lib/types/ifc-model-adapter.d.ts +14 -0
  40. package/lib/types/index.d.ts +8 -0
  41. package/lib/types/input-validator.d.ts +12 -0
  42. package/lib/types/invariant.d.ts +12 -0
  43. package/lib/types/inventory-report-generator.d.ts +22 -0
  44. package/lib/types/policy-basis-builder.d.ts +8 -0
  45. package/lib/types/progress-record-adapter.d.ts +11 -0
  46. package/lib/types/report-desensitizer.d.ts +12 -0
  47. package/lib/types/review-override-recorder.d.ts +21 -0
  48. package/lib/types/sequential-code-allocator.d.ts +10 -0
  49. package/lib/types/source-adapter.d.ts +9 -0
  50. package/lib/types/types.d.ts +157 -0
  51. package/lib/types/unified-asset-merger.d.ts +13 -0
  52. package/lib/types.js +2 -0
  53. package/lib/unified-asset-merger.js +18 -0
  54. package/package.json +74 -5
@@ -0,0 +1,105 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { DEFAULT_CLASSIFICATION_CONFIG_PATH, DEFAULT_ENCODING_RULE_CONFIG_PATH, DEFAULT_SOURCE_ADAPTER_CONFIG_PATH, } from './invariant.js';
4
+ import { defaultClassificationConfig } from './default-classification-config.js';
5
+ import { defaultEncodingRuleConfig } from './default-encoding-rule-config.js';
6
+ export class ConstructionConfigLoader {
7
+ configPath;
8
+ constructor(configPath) {
9
+ this.configPath = configPath ?? process.cwd();
10
+ }
11
+ load() {
12
+ const classificationResult = this.loadClassificationConfig();
13
+ const encodingResult = this.loadEncodingRuleConfig();
14
+ const sourceResult = this.loadSourceAdapterConfig();
15
+ const statuses = [
16
+ classificationResult.status,
17
+ encodingResult.status,
18
+ sourceResult.status,
19
+ ];
20
+ const loadStatus = this.aggregateStatus(statuses);
21
+ return {
22
+ classificationConfig: classificationResult.config,
23
+ encodingRuleConfig: encodingResult.config,
24
+ sourceAdapterConfig: sourceResult.config,
25
+ loadStatus,
26
+ };
27
+ }
28
+ aggregateStatus(statuses) {
29
+ if (statuses.every((s) => s === 'CONFIG_LOADED')) {
30
+ return 'CONFIG_LOADED';
31
+ }
32
+ if (statuses.every((s) => s === 'DEFAULT_MISSING')) {
33
+ return 'DEFAULT_MISSING';
34
+ }
35
+ if (statuses.some((s) => s === 'DEFAULT_PARSE')) {
36
+ return 'DEFAULT_PARSE';
37
+ }
38
+ if (statuses.some((s) => s === 'DEFAULT_VERSION')) {
39
+ return 'DEFAULT_VERSION';
40
+ }
41
+ return 'DEFAULT_PARTIAL';
42
+ }
43
+ loadClassificationConfig() {
44
+ const filePath = resolve(this.configPath, DEFAULT_CLASSIFICATION_CONFIG_PATH);
45
+ if (!existsSync(filePath)) {
46
+ return { config: defaultClassificationConfig, status: 'DEFAULT_MISSING' };
47
+ }
48
+ try {
49
+ const raw = readFileSync(filePath, 'utf-8');
50
+ const parsed = JSON.parse(raw);
51
+ if (!parsed.version || !Array.isArray(parsed.nodes)) {
52
+ return { config: defaultClassificationConfig, status: 'DEFAULT_VERSION' };
53
+ }
54
+ return { config: parsed, status: 'CONFIG_LOADED' };
55
+ }
56
+ catch {
57
+ return { config: defaultClassificationConfig, status: 'DEFAULT_PARSE' };
58
+ }
59
+ }
60
+ loadEncodingRuleConfig() {
61
+ const filePath = resolve(this.configPath, DEFAULT_ENCODING_RULE_CONFIG_PATH);
62
+ if (!existsSync(filePath)) {
63
+ return { config: defaultEncodingRuleConfig, status: 'DEFAULT_MISSING' };
64
+ }
65
+ try {
66
+ const raw = readFileSync(filePath, 'utf-8');
67
+ const parsed = JSON.parse(raw);
68
+ if (!parsed.version || typeof parsed.classificationCodeLength !== 'number') {
69
+ return { config: defaultEncodingRuleConfig, status: 'DEFAULT_VERSION' };
70
+ }
71
+ return { config: parsed, status: 'CONFIG_LOADED' };
72
+ }
73
+ catch {
74
+ return { config: defaultEncodingRuleConfig, status: 'DEFAULT_PARSE' };
75
+ }
76
+ }
77
+ loadSourceAdapterConfig() {
78
+ const filePath = resolve(this.configPath, DEFAULT_SOURCE_ADAPTER_CONFIG_PATH);
79
+ const defaultConfig = {
80
+ version: '1.0.0',
81
+ lastUpdated: '2024-01-01T00:00:00.000Z',
82
+ adapters: [
83
+ { type: 'IFC', adapterClassName: 'IfcModelAdapter', supportedVersions: ['IFC2X3', 'IFC4'] },
84
+ { type: 'CONTRACT', adapterClassName: 'ContractAdapter', supportedVersions: ['1.0'] },
85
+ { type: 'PROGRESS', adapterClassName: 'ProgressRecordAdapter', supportedVersions: ['1.0'] },
86
+ { type: 'ACCEPTANCE', adapterClassName: 'AcceptanceDocAdapter', supportedVersions: ['1.0'] },
87
+ ],
88
+ };
89
+ if (!existsSync(filePath)) {
90
+ return { config: defaultConfig, status: 'DEFAULT_MISSING' };
91
+ }
92
+ try {
93
+ const raw = readFileSync(filePath, 'utf-8');
94
+ const parsed = JSON.parse(raw);
95
+ if (!parsed.version || !Array.isArray(parsed.adapters)) {
96
+ return { config: defaultConfig, status: 'DEFAULT_VERSION' };
97
+ }
98
+ return { config: parsed, status: 'CONFIG_LOADED' };
99
+ }
100
+ catch {
101
+ return { config: defaultConfig, status: 'DEFAULT_PARSE' };
102
+ }
103
+ }
104
+ }
105
+ //# sourceMappingURL=construction-config-loader.js.map
@@ -0,0 +1,57 @@
1
+ import { readFileSync } from 'node:fs';
2
+ export class ContractAdapter {
3
+ adapt(sourcePath, systemId, projectId) {
4
+ const assets = [];
5
+ const warnings = [];
6
+ const errors = [];
7
+ let content;
8
+ try {
9
+ content = readFileSync(sourcePath, 'utf-8');
10
+ }
11
+ catch (e) {
12
+ errors.push(`合同文件读取失败: ${sourcePath} - ${e.message}`);
13
+ return { assets, warnings, errors };
14
+ }
15
+ let records;
16
+ try {
17
+ const parsed = JSON.parse(content);
18
+ records = Array.isArray(parsed) ? parsed : [parsed];
19
+ }
20
+ catch (e) {
21
+ errors.push(`合同文件解析失败: ${sourcePath} - ${e.message}`);
22
+ return { assets, warnings, errors };
23
+ }
24
+ const collectionTime = new Date().toISOString();
25
+ for (const record of records) {
26
+ if (!record || typeof record !== 'object') {
27
+ warnings.push('合同记录格式不合法,已跳过');
28
+ continue;
29
+ }
30
+ if (typeof record.contractId !== 'string' || record.contractId.trim() === '') {
31
+ warnings.push('合同记录缺少contractId,已跳过');
32
+ continue;
33
+ }
34
+ const dataType = this.mapContractTypeToDataType(record.contractType ?? '');
35
+ assets.push({
36
+ assetId: `CONTRACT-${record.contractId}`,
37
+ sourceSystemId: systemId,
38
+ dataType,
39
+ projectId,
40
+ collectionTime,
41
+ classificationCode: '',
42
+ assetCode: '',
43
+ judgmentStatus: '自动判定',
44
+ });
45
+ }
46
+ return { assets, warnings, errors };
47
+ }
48
+ mapContractTypeToDataType(contractType) {
49
+ if (!contractType)
50
+ return '参建方信息-组织角色';
51
+ if (contractType.includes('材料') || contractType.includes('采购')) {
52
+ return '材料清单-组织角色';
53
+ }
54
+ return '参建方信息-组织角色';
55
+ }
56
+ }
57
+ //# sourceMappingURL=contract-adapter.js.map
@@ -0,0 +1,112 @@
1
+ export const defaultClassificationConfig = {
2
+ version: '1.0.0',
3
+ lastUpdated: '2024-01-01T00:00:00.000Z',
4
+ nodes: [
5
+ {
6
+ classificationCode: '10',
7
+ classificationName: '按功能分建筑物',
8
+ parentCode: '',
9
+ level: 1,
10
+ mappedDataTypes: ['BIM构件-建筑物', 'BIM模型-建筑物', '设计图纸-建筑物'],
11
+ },
12
+ {
13
+ classificationCode: '11',
14
+ classificationName: '按形态分建筑物',
15
+ parentCode: '',
16
+ level: 1,
17
+ mappedDataTypes: ['BIM构件-建筑物形态', '设计图纸-建筑物形态'],
18
+ },
19
+ {
20
+ classificationCode: '12',
21
+ classificationName: '按功能分建筑空间',
22
+ parentCode: '',
23
+ level: 1,
24
+ mappedDataTypes: ['BIM构件-建筑空间', 'BIM模型-建筑空间'],
25
+ },
26
+ {
27
+ classificationCode: '13',
28
+ classificationName: '按形态分建筑空间',
29
+ parentCode: '',
30
+ level: 1,
31
+ mappedDataTypes: ['BIM构件-建筑空间形态'],
32
+ },
33
+ {
34
+ classificationCode: '14',
35
+ classificationName: '元素',
36
+ parentCode: '',
37
+ level: 1,
38
+ mappedDataTypes: ['BIM构件-元素', 'BIM模型-元素', '设计图纸-元素'],
39
+ },
40
+ {
41
+ classificationCode: '15',
42
+ classificationName: '工作成果',
43
+ parentCode: '',
44
+ level: 1,
45
+ mappedDataTypes: ['BIM构件-工作成果', '设计图纸-工作成果'],
46
+ },
47
+ {
48
+ classificationCode: '20',
49
+ classificationName: '工程建设项目阶段',
50
+ parentCode: '',
51
+ level: 1,
52
+ mappedDataTypes: ['进度记录-项目阶段', '工序记录-项目阶段'],
53
+ },
54
+ {
55
+ classificationCode: '21',
56
+ classificationName: '行为',
57
+ parentCode: '',
58
+ level: 1,
59
+ mappedDataTypes: ['进度记录-行为', '工序记录-行为', '施工数据-行为'],
60
+ },
61
+ {
62
+ classificationCode: '22',
63
+ classificationName: '专业领域',
64
+ parentCode: '',
65
+ level: 1,
66
+ mappedDataTypes: ['进度记录-专业领域', '工序记录-专业领域', '施工数据-专业领域'],
67
+ },
68
+ {
69
+ classificationCode: '30',
70
+ classificationName: '建筑产品',
71
+ parentCode: '',
72
+ level: 1,
73
+ mappedDataTypes: ['材料清单-建筑产品', '材质信息-建筑产品'],
74
+ },
75
+ {
76
+ classificationCode: '31',
77
+ classificationName: '组织角色',
78
+ parentCode: '',
79
+ level: 1,
80
+ mappedDataTypes: ['材料清单-组织角色', '参建方信息-组织角色'],
81
+ },
82
+ {
83
+ classificationCode: '32',
84
+ classificationName: '工具',
85
+ parentCode: '',
86
+ level: 1,
87
+ mappedDataTypes: ['材料清单-工具'],
88
+ },
89
+ {
90
+ classificationCode: '33',
91
+ classificationName: '信息',
92
+ parentCode: '',
93
+ level: 1,
94
+ mappedDataTypes: ['材料清单-信息', '材质信息-信息'],
95
+ },
96
+ {
97
+ classificationCode: '40',
98
+ classificationName: '材质',
99
+ parentCode: '',
100
+ level: 1,
101
+ mappedDataTypes: ['材料清单-材质', '材质信息-材质', '材料数据-材质'],
102
+ },
103
+ {
104
+ classificationCode: '41',
105
+ classificationName: '属性',
106
+ parentCode: '',
107
+ level: 1,
108
+ mappedDataTypes: ['验收属性', '质量属性', '验收文档-属性', '属性数据'],
109
+ },
110
+ ],
111
+ };
112
+ //# sourceMappingURL=default-classification-config.js.map
@@ -0,0 +1,10 @@
1
+ export const defaultEncodingRuleConfig = {
2
+ version: '1.0.0',
3
+ lastUpdated: '2024-01-01T00:00:00.000Z',
4
+ classificationCodeLength: 5,
5
+ sequentialCodeLength: 4,
6
+ sequentialCodeStart: 1,
7
+ sequentialCodeMax: 9999,
8
+ checksumAlgorithm: 'Luhn',
9
+ };
10
+ //# sourceMappingURL=default-encoding-rule-config.js.map
@@ -0,0 +1,156 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { IFC_ENTITY_TYPES, SUPPORTED_IFC_VERSIONS } from './invariant.js';
3
+ export class IfcModelAdapter {
4
+ adapt(sourcePath, systemId, projectId) {
5
+ const assets = [];
6
+ const warnings = [];
7
+ const errors = [];
8
+ let content;
9
+ try {
10
+ content = readFileSync(sourcePath, 'utf-8');
11
+ }
12
+ catch (e) {
13
+ errors.push(`IFC文件读取失败: ${sourcePath} - ${e.message}`);
14
+ return { assets, warnings, errors };
15
+ }
16
+ const parseResult = this.parseIfc(content, sourcePath);
17
+ warnings.push(...parseResult.warnings);
18
+ errors.push(...parseResult.errors);
19
+ const collectionTime = new Date().toISOString();
20
+ for (const entity of parseResult.entities) {
21
+ const dataType = this.mapEntityTypeToDataType(entity.entityType);
22
+ if (dataType === '') {
23
+ warnings.push(`构件类型 ${entity.entityType} 不支持,已跳过 (line=${entity.lineId})`);
24
+ continue;
25
+ }
26
+ assets.push({
27
+ assetId: `IFC-${entity.guid || entity.lineId}`,
28
+ sourceSystemId: systemId,
29
+ dataType,
30
+ projectId,
31
+ collectionTime,
32
+ classificationCode: '',
33
+ assetCode: '',
34
+ judgmentStatus: '自动判定',
35
+ });
36
+ }
37
+ return { assets, warnings, errors };
38
+ }
39
+ parseIfc(content, filePath) {
40
+ const entities = [];
41
+ const warnings = [];
42
+ const errors = [];
43
+ let version = '';
44
+ const lines = content.split(/\r?\n/);
45
+ for (let i = 0; i < lines.length; i++) {
46
+ const line = lines[i];
47
+ if (line === undefined)
48
+ continue;
49
+ const trimmed = line.trim();
50
+ if (trimmed === '')
51
+ continue;
52
+ if (trimmed.startsWith('FILE_DESCRIPTION')) {
53
+ const versionMatch = trimmed.match(/'([^']+)'/);
54
+ if (versionMatch && versionMatch[1]) {
55
+ const rawVersion = versionMatch[1].toUpperCase();
56
+ if (SUPPORTED_IFC_VERSIONS.some((v) => rawVersion.includes(v))) {
57
+ version = SUPPORTED_IFC_VERSIONS.find((v) => rawVersion.includes(v)) ?? '';
58
+ }
59
+ else {
60
+ version = rawVersion;
61
+ }
62
+ }
63
+ continue;
64
+ }
65
+ const entityMatch = trimmed.match(/^#(\d+)\s*=\s*([A-Z0-9]+)\s*\((.*)\)\s*;?\s*$/);
66
+ if (!entityMatch) {
67
+ if (trimmed.startsWith('#')) {
68
+ errors.push(`IFC格式不合法: ${filePath} line=${i + 1}`);
69
+ }
70
+ continue;
71
+ }
72
+ const lineId = parseInt(entityMatch[1], 10);
73
+ const entityType = entityMatch[2];
74
+ const argsStr = entityMatch[3] ?? '';
75
+ if (!IFC_ENTITY_TYPES.includes(entityType)) {
76
+ warnings.push(`构件类型 ${entityType} 不支持,已跳过 (line=${i + 1})`);
77
+ continue;
78
+ }
79
+ const guid = this.extractGuid(argsStr);
80
+ const attributes = this.extractAttributes(argsStr);
81
+ entities.push({ lineId, entityType, guid, attributes });
82
+ }
83
+ if (version === '') {
84
+ version = 'IFC2X3';
85
+ warnings.push('未检测到IFC版本,默认按IFC2X3解析');
86
+ }
87
+ return { entities, warnings, errors, version };
88
+ }
89
+ extractGuid(argsStr) {
90
+ const guidMatch = argsStr.match(/^'([^']*)'/);
91
+ return guidMatch && guidMatch[1] ? guidMatch[1] : '';
92
+ }
93
+ extractAttributes(argsStr) {
94
+ const attributes = [];
95
+ let depth = 0;
96
+ let current = '';
97
+ for (const char of argsStr) {
98
+ if (char === '(') {
99
+ depth++;
100
+ if (depth === 1)
101
+ continue;
102
+ }
103
+ if (char === ')') {
104
+ depth--;
105
+ if (depth === 0) {
106
+ attributes.push(current);
107
+ current = '';
108
+ continue;
109
+ }
110
+ }
111
+ if (depth >= 1) {
112
+ current += char;
113
+ }
114
+ else if (char === ',') {
115
+ if (current.trim() !== '') {
116
+ attributes.push(current.trim());
117
+ }
118
+ current = '';
119
+ }
120
+ else {
121
+ current += char;
122
+ }
123
+ }
124
+ if (current.trim() !== '') {
125
+ attributes.push(current.trim());
126
+ }
127
+ return attributes;
128
+ }
129
+ mapEntityTypeToDataType(entityType) {
130
+ const mapping = {
131
+ IFCWALL: 'BIM构件-元素',
132
+ IFCWALLSTANDARDCASE: 'BIM构件-元素',
133
+ IFCCOLUMN: 'BIM构件-元素',
134
+ IFCCOLUMNSTANDARDCASE: 'BIM构件-元素',
135
+ IFCSLAB: 'BIM构件-元素',
136
+ IFCSLABSTANDARDCASE: 'BIM构件-元素',
137
+ IFCDOOR: 'BIM构件-元素',
138
+ IFCWINDOW: 'BIM构件-元素',
139
+ IFCBEAM: 'BIM构件-元素',
140
+ IFCBEAMSTANDARDCASE: 'BIM构件-元素',
141
+ IFCFOOTING: 'BIM构件-元素',
142
+ IFCSTAIR: 'BIM构件-元素',
143
+ IFCSTAIRFLIGHT: 'BIM构件-元素',
144
+ IFCRAILING: 'BIM构件-元素',
145
+ IFCCURTAINWALL: 'BIM构件-元素',
146
+ IFCROOF: 'BIM构件-元素',
147
+ IFCSPACE: 'BIM构件-建筑空间',
148
+ IFCBUILDINGSTOREY: 'BIM构件-建筑物',
149
+ IFCBUILDING: 'BIM构件-建筑物',
150
+ IFCSITE: 'BIM构件-建筑物',
151
+ IFCPROPERTYSET: '属性数据',
152
+ };
153
+ return mapping[entityType] ?? '';
154
+ }
155
+ }
156
+ //# sourceMappingURL=ifc-model-adapter.js.map